成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

connect-history-api-fallback分析

jsummer / 2082人閱讀

摘要:研究下,地址,當然它也可以作為的中間件使用中介紹的很清楚解釋一下首頁比如我使用訪問,發(fā)現(xiàn)顯示,點擊,顯示,地址欄變?yōu)?,一切正常,這時候刷新當前頁面或或點擊瀏覽器的刷新按鈕或在地址欄上再敲一下回車,發(fā)現(xiàn)了哦文檔

研究下connect-history-api-fallback v1.3.0,地址:https://github.com/bripkens/c...,當然它也可以作為express的中間件使用

README中介紹的很清楚

Single Page Applications (SPA) typically only utilise one index file that is accessible by web browsers: usually index.html. Navigation in the application is then commonly handled using JavaScript with the help of the HTML5 History API. This results in issues when the user hits the refresh button or is directly accessing a page other than the landing page, e.g. /help or /help/online as the web server bypasses the index file to locate the file at this location. As your application is a SPA, the web server will fail trying to retrieve the file and return a 404 - Not Found message to the user.

This tiny middleware addresses some of the issues. Specifically, it will change the requested location to the index you specify (default being /index.html) whenever there is a request which fulfills the following criteria:

The request is a GET request

which accepts text/html,

is not a direct file request, i.e. the requested path does not contain a . (DOT) character and

does not match a pattern provided in options.rewrites (see options below)

解釋一下:

server.js

const path = require("path")

const express = require("express")
const router = express.Router()

const indexRoute = router.get("/", (req, res) => {
  res.status(200).render("index", {
    title: "首頁"
  })
})

app.set("views", path.join(__dirname, "templates"))
app.set("view engine", "html")
app.engine("html", ejs.__express)

app.use("/static", express.static(path.join(__dirname, "public")))

app.use(history({
  rewrites: [
    { from: /^/abc$/, to: "/" }
  ]
}))

app.get("/", indexRoute)

app.use((req, res) => {
  res.status(404).send("File not found!")
})

app.listen(9090, "127.0.0.1", () => {
  console.log("ther server is running at port " + 9090)
})

index.html

index.js

Vue.use(VueRouter)

var s = "
Go to Foo - Go to Bar - Go to Home
" var Home = { template: "
" + s + "
home
" + "
", created: function() { console.log("home") } } var Foo = { template: "
" + s + "
foo
" + "
", created: function() { console.log("foo") }} var Bar = { template: "
" + s + "
bar
" + "
", created: function() { console.log("bar") }} var NotFoundComponent = { template: "
" + s + "
not found
" + "
", created: function() { console.log("not found") }} var routes = [ { path: "/", component: Home }, { path: "/foo", component: Foo }, { path: "/bar", component: Bar }, { path: "*", component: NotFoundComponent } ] var router = new VueRouter({ mode: "history", routes: routes }) new Vue({ router: router }).$mount("#test")

比如我使用vue-router, 訪問http://localhost:9090,發(fā)現(xiàn)顯示home,點擊Go to Foo,顯示foo,地址欄變?yōu)閔ttp://localhost:9090/foo,一切正常,ok
這時候刷新當前頁面(ctrl+R或ctrl+command+R或點擊瀏覽器的刷新按鈕或在地址欄上再敲一下回車),發(fā)現(xiàn)404了哦
vue-router文檔針對這種情況做了很好的解釋:

Not to worry: To fix the issue, all you need to do is add a simple catch-all fallback route to your server. If the URL doesn"t match any static assets, it should serve the same index.html page that your app lives in. Beautiful, again!

如果express server使用了connect-history-api-fallback middleware,在你定義router的前面app.use(history({ rewrites: [ { from: /^/abc$/, to: "/" } ] }))一下

再刷新頁面,發(fā)現(xiàn)地址仍然http://localhost:9090/foo,然而走進了咱們的前端路由,chrome控制臺顯示了foo,真的是beautiful again

其實過程也很簡單啦,請求/foo,走到了咱們的history-api-fallback中間件,然后他看你沒有rewrite,那么好,我把req.url改成"/",于是vue-router發(fā)現(xiàn)地址/foo,所以根據(jù)routes的map,渲染了Foo組件

但是萬一有人輸入地址/abc,怎么辦? vue-router定義了{ path: "*", component: NotFoundComponent }用來catch-all route within your Vue app to show a 404 page

Alternatively, if you are using a Node.js server, you can implement the fallback by using the router on the server side to match the incoming URL and respond with 404 if no route is matched.

地址輸入/abc,回車,走到vue-router,會顯示not found

地址輸入/xyz,回車,走到服務(wù)端路由,http狀態(tài)為404,然后顯示File not found!

source code 分析

貼下代碼

"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);
        logger("Rewriting", req.method, req.url, "to", rewriteTarget);
        req.url = rewriteTarget;
        return next();
      }
    }

    if (parsedUrl.pathname.indexOf(".") !== -1 &&
        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) {
  if (typeof rule === "string") {
    return rule;
  } else if (typeof rule !== "function") {
    throw new Error("Rewrite rule can only be of type string of function.");
  }

  return rule({
    parsedUrl: parsedUrl,
    match: match
  });
}

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(){};
}

getLogger, 默認不輸出,options.verbose為true,則默認console.log.bind(console),但不知道這里bind意義何在 - -,也可以直接傳logger,比如debug

如果req.method != "GET",灰,結(jié)束
如果!headers || !headers.accept != "string" (有這情況?),灰,結(jié)束
如果headers.accept.indexOf("application/json") === 0,灰,結(jié)束

acceptsHtml函數(shù)a判斷headers.accept字符串是否含有["text/html", "/"]中任意一個
當然不夠這兩個不夠你可以自定義到選項options.htmlAcceptHeaders中
!acceptsHtml(headers.accept, options),灰,結(jié)束

然后根據(jù)你定義的選項rewrites(沒定義就相當于跳過了)
按定義的數(shù)組順序,字符串依次匹配路由rewrite.from,匹配成功則走rewrite.to,to可以是字符串也可以是函數(shù),綠,結(jié)束

判斷dot file,即pathname中包含.(點),并且選項disableDotRule !== true,即沒有關(guān)閉點文件限制規(guī)則,灰,結(jié)束
那么剩下的情況(parsedUrl.pathname不含點,或者含點但關(guān)閉了點文件規(guī)則)
rewriteTarget = options.index || "/index.html",綠結(jié)束

稍微注意下,他是先匹配自定義rewrites規(guī)則,再匹配點文件規(guī)則

測試部分

用的是nodeunit,具體用法https://github.com/caolan/nod...
隨便看兩個測試用例

var sinon = require("sinon");
var historyApiFallback = require("../lib");

var tests = module.exports = {};

var middleware;
var req = null;
var requestedUrl;
var next;

tests.setUp = function(done) {
  middleware = historyApiFallback();
  requestedUrl = "/foo";
  req = {
    method: "GET",
    url: requestedUrl,
    headers: {
      accept: "text/html, */*"
    }
  };
  next = sinon.stub();

  done();
};

// ....

tests["should ignore requests that do not accept html"] = function(test) {
  req.headers.accept = "application/json";
  // 調(diào)用middleware
  middleware(req, null, next);
  // 測試req.url是否等于requestedUrl
  test.equal(req.url, requestedUrl);
  // next是否被調(diào)用過
  test.ok(next.called);
  // 測試結(jié)束
  test.done();
};

// ...

tests["should rewrite requests when the . rule is disabled"] = function(test) {
  req.url = "js/app.js";
  middleware = historyApiFallback({
    disableDotRule: true
  });
  middleware(req, null, next);
  // 測試req.url是否等于/index.html
  // 因為pathname中有點,且關(guān)閉了點規(guī)則
  // req.url應(yīng)該被rewrit成了/index.html
  test.equal(req.url, "/index.html");
  test.ok(next.called);
  test.done();
};

// ...
tests["should test rewrite rules"] = function(test) {
  req.url = "/socer";
  middleware = historyApiFallback({
    rewrites: [
      {from: //soccer/, to: "/soccer.html"}
    ]
  });
     
  middleware(req, null, next);
  // 因為沒有匹配上rewrites里的規(guī)則
  // 而req.url pathname又不含點
  // 所以req.url 倒退到了index.html
  test.equal(req.url, "/index.html");
  test.ok(next.called);
  test.done();
};

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/86595.html

相關(guān)文章

  • 前端臨床手札——webpack構(gòu)建逐步解構(gòu)(上)

    摘要:前言由于博主最近又閑下來了,之前覺得的官方文檔比較難啃一直放到現(xiàn)在。文章會逐步分析每個處理的用意當然是博主自己的理解,不足之處歡迎指出溝通交流。后續(xù)將會補上構(gòu)建生產(chǎn)的配置分析,案例參考。前端臨床手札構(gòu)建逐步解構(gòu)下 前言 由于博主最近又閑下來了,之前覺得webpack的官方文檔比較難啃一直放到現(xiàn)在。細心閱讀多個webpack配置案例后覺得還是得自己寫個手腳架,當然這個案例是基于vue的,...

    lowett 評論0 收藏0
  • 網(wǎng)站子目錄部署VUE webpack 打包資源文件路徑的正確引用方式

    摘要:是目前使用最為火熱的打包工具,各大知名的框架類庫都用其打包,國內(nèi)使用最近也火熱起來。但是坑也很多,比如說圖片,字體等文件的路徑。 webpack 是目前使用最為火熱的打包工具,各大知名的框架類庫都用其打包,國內(nèi)使用最近也火熱起來。它在單頁應(yīng)用和類庫打包上幫助許多人從代碼管理中解脫了出來,成為了當下風(fēng)靡一時的打包工具。 但是坑也很多,比如說圖片,字體等文件的路徑。 剛開始用webpack...

    zgbgx 評論0 收藏0
  • vue-cli 項目結(jié)構(gòu)

    摘要:項目結(jié)構(gòu)為我們搭建開發(fā)所需要的環(huán)境目錄結(jié)構(gòu)及主要功能項目構(gòu)建相關(guān)代碼生產(chǎn)環(huán)境構(gòu)建代碼檢查等版本熱重載相關(guān)構(gòu)建本地服務(wù)器構(gòu)建工具相關(guān)基礎(chǔ)配置開發(fā)環(huán)境配置生產(chǎn)環(huán)境配置項目開發(fā)環(huán)境配置開發(fā)環(huán)境 Vue-cli 項目結(jié)構(gòu) vue-cli 為我們搭建開發(fā)所需要的環(huán)境 目錄結(jié)構(gòu)及主要功能 |-- build // 項目構(gòu)建(webpack)...

    int64 評論0 收藏0
  • vue-cli 項目結(jié)構(gòu)

    摘要:項目結(jié)構(gòu)為我們搭建開發(fā)所需要的環(huán)境目錄結(jié)構(gòu)及主要功能項目構(gòu)建相關(guān)代碼生產(chǎn)環(huán)境構(gòu)建代碼檢查等版本熱重載相關(guān)構(gòu)建本地服務(wù)器構(gòu)建工具相關(guān)基礎(chǔ)配置開發(fā)環(huán)境配置生產(chǎn)環(huán)境配置項目開發(fā)環(huán)境配置開發(fā)環(huán)境 Vue-cli 項目結(jié)構(gòu) vue-cli 為我們搭建開發(fā)所需要的環(huán)境 目錄結(jié)構(gòu)及主要功能 |-- build // 項目構(gòu)建(webpack)...

    Markxu 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<