expressはvue-routerのhistoryを使ってピットを踏んでいます。
13313 ワード
vue-routerデフォルトhashモード――URLのhashを使って一つの完全なURLをシミュレーションするので、URLが変更されると、ページは再ロードされない。
丑いhashを望まないなら、経路のhistoryモードを利用して、history.pusState APIを十分に利用してURLのジャンプを完成します。ページを再ロードする必要はありません。
historyモードを使用すると、URLは通常のurlのようになります。 yoursite.com/user/idも綺麗です。
個人的な理解
上は公式の説明です。文書の一貫したスタイルはわかる人にだけ見せます。二年前に私が今より料理を返していた時、この話を見たら彼はハンマーを言っていました。直接飛び越しました。
言わないでください。hammer:直接挙げます。chestnut:
普通の私達はプロジェクトをサーバーに置いて、ルートはすべてサーバーの中で設定したのです。
例えばサイト https://www.text.com/ 中adminディレクトリの下に一つあります。 login.のページ。ユーザが入力すると https://www.text.com/admin/login を選択します www.text.comドメイン名の部分はサーバーipとポート番号を取得し、ipとポート番号に基づいて対応するサーバの対応するプログラムを見つけ、プログラム解析を行う。 /admin/login経路が分かりました。あなたが探しているのはadminディレクトリの下です。 ロゴページを返します。
これは正常な方式で、サーバーは1つのルートを制御して1つのページのファイル(リダイレクトの情況を考慮しません)を指して、このように私達のプロジェクトは普通はいくつのページがいくつありますか?
vueの中で、私達が包装したファイルは一つだけです。 index.はすべてこのページで行われます。ユーザーのすべてのルートは実はすべて要求しています。 index.ページ。
vueプロジェクトを積載すると仮定します。 index.もadminディレクトリの下で、vueプロジェクトの中にloginページがあります。その対応するurlはです。 https://www.text.com/admin/#/login 。
このurlは三つの部分からなっています。 wwww.text.comはドメイン名で、 /adminはプロジェクトの所在ディレクトリで、上と同じようにこの解析作業はサーバーで行い、サーバが解析しました。 /adminのルートは、あなたに戻ってきます。 index. /#/loginはvue-routerシミュレーションのルートです。ページのすべてのジャンプはvueにあります。 index.で完成したので、ページ内の切り替えを示します。ホームページに切り替えたら、対応するファイルはまだですか? index. https://www.text.com/admin/#/home 、vue-routerが判断しました。 /#/homeの変更によってページdomの要素が変わり、ユーザーにページがジャンプしたような感じを与えます。これがshモードです。
正常なurlとhashモードの違いは、ページのjsコードがサーバでルートを判断する行為を取得できないので、このような方法でしかルートの機能を実現できないことが分かりました。
historyモードとは、vueのルートを通常のurlと同じにすることです。どうすればいいですか?
なぜ実現が必要ですか?
どうするかという前に、なぜhistoryモードが必要なのかを話してください。公式文書によると、このほうがいいです。emmmmは、直接消費者向けのウェブサイトの美しさについて、これは確かに問題があります。 /# 気弱に見える。企業管理のspaについては、これは何もないです。
だから美しい以外に、historyモードは他の長所があります。
私達は知っています。ページがアンカーポイントを使うなら、それは一つです。 ラベル、 クレックしても、スペルの中にidがmark 1のラルがあれば自动的に対応するラベルベルにスコールがありますが、urlの后ろには追加されます。 #マルク.問題はここです。hash mo doを使う。 #markはvue-routerシミショーのルートを入れます。例ええばこれ ラベルは上记のロゴペです。クリークしたらurlから https://www.text.com/admin/#/login になります https://www.text.com/admin/#/mark 。wtf?正常には問題が大きいです。アンカスポーツポントはスクロロールです。jsシューはです。でも、マ`クダウンのタイトナビゲーム机能を実现したのです。この机能はプラグインであります。やはりリプライはhistoryを使います。利害関系の下です。やはりhistory more doを使って仕事量が少ないです。どのようにしますか?何を知っていますか?以上、なぜ、次はどうしますか?公式文書には「詳細」という説明がありますが、これはとも難しいです。原理も簡単です。上记のように、vue-routerがhash more doを采用している最大の理由は、してのルーティンテが判断する行为を行うために必要な场合です。原理とは、ユザが力に入ったルートが何であるかを教えてくれます。 index.ファルは、jsがルートに従っています。レンダリングします。公式仕様によリ、フロトエッドのrouter配置に属性を追加しました。以下の通りです。 const router=new Vue Router({ mode:'history'は、 routes:[…] } バークエッドの私は詳しく説明します。私はexpressを使っています。直接connect-history-api-fallbackの中間部品を使用しました。中间メ`ルアドレス https://github.com/bripkens/connect-history-api-fallback)
本来なら大丈夫ですが、ガチョウはサーバーに入れてから、蛾が出てきます。静的なファイルの読み込み時にインターフェースの戻りはすべて
We're sorry but client doesn't work properly without JavaScript enabled.Please enable it to conuetin.
文字通り、私のプロジェクトがJavaScriptを有効にしていないと意味が分かりません。そこで、慎重にコンソールのrequest headersとrequest headersを比較して、いくつかの猫のねばねばねばしたことを発見しました。要求ヘッドのacceptとレスポンスヘッドのcontent-typeが一致しません。cssファイル要求ヘッドのacceptはtext/cssです。応答ヘッドのcontentt-typeはtext/typeです。これは何かに応答するべきではないですか?私は崔のウグイスのような女性が妻になりたいです。杜十娘にも認めてもらいました。結果として、パンキンレン全体を私にあげたらどうなりますか?
どこが問題なのか全く分かりません。googleでも方法が見つかりませんでした。とっさに思いつきました。間に合わないなら、手動でアップしてもいいですか?express.staticのsetHeadersでファイルの種類をチェックして、ファイルの種類によって手動でmime typeを設定します。私は自分の機転に感心し始めました。
次のコードは、acceptsHtml関数の内部設定htmlAcceptHeadersのデフォルト値です。 'text/html、'*/*'要求ヘッダのacceptを判断して、説明に一致したらtrueに戻ります。そうでなければfalseに戻ります。直接デフォルトのインターフェースでcssとjsに正常に戻りません。 'text/html'は、'aplication/xhtml+xml'で実行できます。これは不思議です。httlAccept Headersはどうしてcssとjsに影響しますか?遅すぎて、あまり気にしなくて、簡単で乱暴にソースを抜き出して直接プロジェクトの中に入れて走ってみて、いったい何が起こったのか見てください。
文書を書く人の論理に問題があるのではなく、彼は怠け者で、説明したくないのです。
ピット2
もう一つ注意したいのは、ルート名の設定です。やはりこのURLです https://www.text.com/admin/login を選択します。 /adminのルートはすべてvueのを指しました。 index.ファイル、hashモードの下で私達のルートはこのように構成されています。
たとえば上の例を変えて、このような状況の問題を避けることができます。
https://router.vuejs.org/zh/guide/essentials/history-mode.html#バックエンド設定例
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。
丑いhashを望まないなら、経路のhistoryモードを利用して、history.pusState APIを十分に利用してURLのジャンプを完成します。ページを再ロードする必要はありません。
historyモードを使用すると、URLは通常のurlのようになります。 yoursite.com/user/idも綺麗です。
個人的な理解
上は公式の説明です。文書の一貫したスタイルはわかる人にだけ見せます。二年前に私が今より料理を返していた時、この話を見たら彼はハンマーを言っていました。直接飛び越しました。
言わないでください。hammer:直接挙げます。chestnut:
普通の私達はプロジェクトをサーバーに置いて、ルートはすべてサーバーの中で設定したのです。
例えばサイト https://www.text.com/ 中adminディレクトリの下に一つあります。 login.のページ。ユーザが入力すると https://www.text.com/admin/login を選択します www.text.comドメイン名の部分はサーバーipとポート番号を取得し、ipとポート番号に基づいて対応するサーバの対応するプログラムを見つけ、プログラム解析を行う。 /admin/login経路が分かりました。あなたが探しているのはadminディレクトリの下です。 ロゴページを返します。
これは正常な方式で、サーバーは1つのルートを制御して1つのページのファイル(リダイレクトの情況を考慮しません)を指して、このように私達のプロジェクトは普通はいくつのページがいくつありますか?
vueの中で、私達が包装したファイルは一つだけです。 index.はすべてこのページで行われます。ユーザーのすべてのルートは実はすべて要求しています。 index.ページ。
vueプロジェクトを積載すると仮定します。 index.もadminディレクトリの下で、vueプロジェクトの中にloginページがあります。その対応するurlはです。 https://www.text.com/admin/#/login 。
このurlは三つの部分からなっています。 wwww.text.comはドメイン名で、 /adminはプロジェクトの所在ディレクトリで、上と同じようにこの解析作業はサーバーで行い、サーバが解析しました。 /adminのルートは、あなたに戻ってきます。 index. /#/loginはvue-routerシミュレーションのルートです。ページのすべてのジャンプはvueにあります。 index.で完成したので、ページ内の切り替えを示します。ホームページに切り替えたら、対応するファイルはまだですか? index. https://www.text.com/admin/#/home 、vue-routerが判断しました。 /#/homeの変更によってページdomの要素が変わり、ユーザーにページがジャンプしたような感じを与えます。これがshモードです。
正常なurlとhashモードの違いは、ページのjsコードがサーバでルートを判断する行為を取得できないので、このような方法でしかルートの機能を実現できないことが分かりました。
historyモードとは、vueのルートを通常のurlと同じにすることです。どうすればいいですか?
なぜ実現が必要ですか?
どうするかという前に、なぜhistoryモードが必要なのかを話してください。公式文書によると、このほうがいいです。emmmmは、直接消費者向けのウェブサイトの美しさについて、これは確かに問題があります。 /# 気弱に見える。企業管理のspaについては、これは何もないです。
だから美しい以外に、historyモードは他の長所があります。
私達は知っています。ページがアンカーポイントを使うなら、それは一つです。 ラベル、 クレックしても、スペルの中にidがmark 1のラルがあれば自动的に対応するラベルベルにスコールがありますが、urlの后ろには追加されます。 #マルク.問題はここです。hash mo doを使う。 #markはvue-routerシミショーのルートを入れます。例ええばこれ ラベルは上记のロゴペです。クリークしたらurlから https://www.text.com/admin/#/login になります https://www.text.com/admin/#/mark 。wtf?正常には問題が大きいです。アンカスポーツポントはスクロロールです。jsシューはです。でも、マ`クダウンのタイトナビゲーム机能を実现したのです。この机能はプラグインであります。やはりリプライはhistoryを使います。利害関系の下です。やはりhistory more doを使って仕事量が少ないです。どのようにしますか?何を知っていますか?以上、なぜ、次はどうしますか?公式文書には「詳細」という説明がありますが、これはとも難しいです。原理も簡単です。上记のように、vue-routerがhash more doを采用している最大の理由は、してのルーティンテが判断する行为を行うために必要な场合です。原理とは、ユザが力に入ったルートが何であるかを教えてくれます。 index.ファルは、jsがルートに従っています。レンダリングします。公式仕様によリ、フロトエッドのrouter配置に属性を追加しました。以下の通りです。 const router=new Vue Router({ mode:'history'は、 routes:[…] } バークエッドの私は詳しく説明します。私はexpressを使っています。直接connect-history-api-fallbackの中間部品を使用しました。中间メ`ルアドレス https://github.com/bripkens/connect-history-api-fallback)
const history = require('connect-history-api-fallback')
app.use(history({
rewrites: [
{
from: /^\/.*$/,
to: function (context) {
return "/";
}
},
]
}));
app.get('/', function (req, res) {
res.sendFile(path.join(process.cwd(), "client/index.html"));
});
app.use(
express.static(
path.join(process.cwd(), "static"),
{
maxAge: 0,// cdn
}
)
);
ピット1本来なら大丈夫ですが、ガチョウはサーバーに入れてから、蛾が出てきます。静的なファイルの読み込み時にインターフェースの戻りはすべて
We're sorry but client doesn't work properly without JavaScript enabled.Please enable it to conuetin.
文字通り、私のプロジェクトがJavaScriptを有効にしていないと意味が分かりません。そこで、慎重にコンソールのrequest headersとrequest headersを比較して、いくつかの猫のねばねばねばしたことを発見しました。要求ヘッドのacceptとレスポンスヘッドのcontent-typeが一致しません。cssファイル要求ヘッドのacceptはtext/cssです。応答ヘッドのcontentt-typeはtext/typeです。これは何かに応答するべきではないですか?私は崔のウグイスのような女性が妻になりたいです。杜十娘にも認めてもらいました。結果として、パンキンレン全体を私にあげたらどうなりますか?
どこが問題なのか全く分かりません。googleでも方法が見つかりませんでした。とっさに思いつきました。間に合わないなら、手動でアップしてもいいですか?express.staticのsetHeadersでファイルの種類をチェックして、ファイルの種類によって手動でmime typeを設定します。私は自分の機転に感心し始めました。
app.use(
express.static(
path.join(process.cwd(), "static"),
{
maxAge: 0,
setHeaders(res,path){
// path , mime type。
}
}
)
);
キャッシュ時間を0に設定し、CDNを消します。この時すでに夜11時になりました。もう絶望しました。最後にconnect-history-appi-fallbackの文書を見ました。htmlept Headersの配置に違和感を感じました。他のものは何の意味が分かりますか?これだけはどうしても理解できません。
const history = require('connect-history-api-fallback')
app.use(history({
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml']
rewrites: [
{
from: /^\/.*$/,
to: function (context) {
return "/";
}
},
]
}));
いったい誰が書いたのですか?静的なファイルのheadersのacceptsとhtmlAccept Headersは何の関係がありますか?私も知らないです。聞くところがありません。この事は長い間私の時間をつぶしてしまいました。研究しないと気持ちが悪いです。古いルールは、connect-history-appi-fallbackソースを見ます。
'use strict';
var url = require('url');
exports = module.exports = function historyApiFallback(options) {
options = options || {};
var logger = getLogger(options);
return function(req, res, next) {
var headers = req.headers;
if (req.method !== 'GET') {
logger(
'Not rewriting',
req.method,
req.url,
'because the method is not GET.'
);
return next();
} else if (!headers || typeof headers.accept !== 'string') {
logger(
'Not rewriting',
req.method,
req.url,
'because the client did not send an HTTP accept header.'
);
return next();
} else if (headers.accept.indexOf('application/json') === 0) {
logger(
'Not rewriting',
req.method,
req.url,
'because the client prefers JSON.'
);
return next();
} else if (!acceptsHtml(headers.accept, options)) {
logger(
'Not rewriting',
req.method,
req.url,
'because the client does not accept HTML.'
);
return next();
}
var parsedUrl = url.parse(req.url);
var rewriteTarget;
options.rewrites = options.rewrites || [];
for (var i = 0; i < options.rewrites.length; i++) {
var rewrite = options.rewrites[i];
var match = parsedUrl.pathname.match(rewrite.from);
if (match !== null) {
rewriteTarget = evaluateRewriteRule(parsedUrl, match, rewrite.to, req);
if(rewriteTarget.charAt(0) !== '/') {
logger(
'We recommend using an absolute path for the rewrite target.',
'Received a non-absolute rewrite target',
rewriteTarget,
'for URL',
req.url
);
}
logger('Rewriting', req.method, req.url, 'to', rewriteTarget);
req.url = rewriteTarget;
return next();
}
}
var pathname = parsedUrl.pathname;
if (pathname.lastIndexOf('.') > pathname.lastIndexOf('/') &&
options.disableDotRule !== true) {
logger(
'Not rewriting',
req.method,
req.url,
'because the path includes a dot (.) character.'
);
return next();
}
rewriteTarget = options.index || '/index.html';
logger('Rewriting', req.method, req.url, 'to', rewriteTarget);
req.url = rewriteTarget;
next();
};
};
function evaluateRewriteRule(parsedUrl, match, rule, req) {
if (typeof rule === 'string') {
return rule;
} else if (typeof rule !== 'function') {
throw new Error('Rewrite rule can only be of type string or function.');
}
return rule({
parsedUrl: parsedUrl,
match: match,
request: req
});
}
function acceptsHtml(header, options) {
options.htmlAcceptHeaders = options.htmlAcceptHeaders || ['text/html', '*/*'];
for (var i = 0; i < options.htmlAcceptHeaders.length; i++) {
if (header.indexOf(options.htmlAcceptHeaders[i]) !== -1) {
return true;
}
}
return false;
}
function getLogger(options) {
if (options && options.logger) {
return options.logger;
} else if (options && options.verbose) {
return console.log.bind(console);
}
return function(){};
}
このコードは分かりやすくて、行を分析しません。直接キーコードを切り取ります。
else if (!acceptsHtml(headers.accept, options)) {
logger(
'Not rewriting',
req.method,
req.url,
'because the client does not accept HTML.'
);
return next();
}
function acceptsHtml(header, options) {
//
options.htmlAcceptHeaders = options.htmlAcceptHeaders || ['text/html', '*/*'];
for (var i = 0; i < options.htmlAcceptHeaders.length; i++) {
if (header.indexOf(options.htmlAcceptHeaders[i]) !== -1) {
return true;
}
}
return false;
}
前のコードが、acceptsHtml関数がfalseに戻ると、ブラウザがファイルを受け付けないと説明し、next()をスキップして実行します。次のコードは、acceptsHtml関数の内部設定htmlAcceptHeadersのデフォルト値です。 'text/html、'*/*'要求ヘッダのacceptを判断して、説明に一致したらtrueに戻ります。そうでなければfalseに戻ります。直接デフォルトのインターフェースでcssとjsに正常に戻りません。 'text/html'は、'aplication/xhtml+xml'で実行できます。これは不思議です。httlAccept Headersはどうしてcssとjsに影響しますか?遅すぎて、あまり気にしなくて、簡単で乱暴にソースを抜き出して直接プロジェクトの中に入れて走ってみて、いったい何が起こったのか見てください。
function acceptsHtml(header, options) {
options.htmlAcceptHeaders = options.htmlAcceptHeaders || ['text/html', '*/*'];
console.log("header", header);
console.log("htmlAcceptHeaders", options.htmlAcceptHeaders);
for (var i = 0; i < options.htmlAcceptHeaders.length; i++) {
console.log("indexOf", header.indexOf(options.htmlAcceptHeaders[i]));
if (header.indexOf(options.htmlAcceptHeaders[i]) !== -1) {
return true;
}
}
return false;
}
htmlAccept Headersの値を設定します。 'text/html,'appication/xhtml+xml'
header text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
htmlAcceptHeaders [ 'text/html', 'application/xhtml+xml' ]
indexOf 0
header text/css,*/*;q=0.1
htmlAcceptHeaders [ 'text/html', 'application/xhtml+xml' ]
indexOf -1
indexOf -1
hml Accept Headersは設定しません。
header text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
htmlAcceptHeaders [ 'text/html', '*/*' ]
indexOf 0
header application/signed-exchange;v=b3;q=0.9,*/*;q=0.8
htmlAcceptHeaders [ 'text/html', '*/*' ]
indexOf -1
indexOf 39
この時に私は急に茅栓が開きました。httlAcccept Headersという属性でcssとjsファイルをフィルタリングします。もしデフォルトで使うならば。 'text/html、'*/*'属性、cssとjsファイルが一致します。その後しばらくの処理で応答ヘッダのmimeファイルタイプが変化します。 text/htmlにより、ブラウザが解析できなくなりました。文書を書く人の論理に問題があるのではなく、彼は怠け者で、説明したくないのです。
ピット2
もう一つ注意したいのは、ルート名の設定です。やはりこのURLです https://www.text.com/admin/login を選択します。 /adminのルートはすべてvueのを指しました。 index.ファイル、hashモードの下で私達のルートはこのように構成されています。
const router = new VueRouter({
routes: [{
path: "/login",
name: "login",
component: login
}]
})
この時私たちはヒットマンモードに変更しました。
const router = new VueRouter({
mode: 'history',
routes: [{
path: "/login",
name: "login",
component: login
}]
})
urlを開く https://www.text.com/admin/login 自動的にジャンプが見つかります。 https://www.text.com/login その理由は /adminのルートはすべてvueのを指しました。 index.htmlファイルの後、jsは私達のコードによってurlを変えました。 https://www.text.com/login ページを更新しないと問題がないです。ページ内のすべてのジャンプはまだvue-routerコントロールです。 index.このファイルは変わりません。しかし、ページを更新すると問題が発生し、サーバーが改めて判断します。 /loginは対応するファイルをルーティングします。したがって、historyモードを使用する場合は、フロントエンドにvue-routerを配置する場合も、バックグラウンドの項目所在ディレクトリを考慮する必要があります。たとえば上の例を変えて、このような状況の問題を避けることができます。
const router = new VueRouter({
mode: 'history',
routes: [{
path: "/admin/login",
name: "login",
component: login
}]
})
参照リンクhttps://router.vuejs.org/zh/guide/essentials/history-mode.html#バックエンド設定例
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。