webpack搭建React項目(3)

上篇文章簡單介紹瞭如下webpack內部WDS的使用,這節討論一下WDS內部proxy的配置方式。前端

devServer

webpack-devServer,通常簡稱WDS,是 webpack 內置的用於開發環境的服務器配置。webpack自己提供三種方式用於開發環境修改代碼之後自動編譯,以提升開發效率:node

整體來講,WDS 配置最容易,而且提供 HMR 的功能,只須要配置devServer.hot: true就直接啓用,方便到了極致!下面就重點看一下 WDS 的proxy配置。web

http-proxy-middleware

webpack的 WDS 內置的proxy功能來自於http-proxy-middleware這個第三方工具,正如我之前看到的一句話所說,開源最重要的不是貢獻本身的代碼,而是把別人的拿過來用,從開源社區的發展角度來看,這的確是核心,只有開源帶動開源,才能讓社區氛圍更好。正則表達式

廢話很少說了,來看一下http-proxy-middleware都有哪些配置吧。json

配置

URL

在瞭解詳細配置以前,先來回顧一下 HTTP 協議下 URL 的構成:api

http-proxy-middleware自己融合了http-proxy的一些配置,可是文檔配置寫的比較抽象,而且多數配置實際開發的時候根本用不到,這裏重點關注幾個比較重要的屬性。瀏覽器

target | string

target用於指定代理轉發的目標域名,在 WDS 中能夠按照以下設置,這樣當本地請求localhost:3000/api的時候,就會被 WDS 轉發請求https://xxx.com/api去

devServer: {  proxy: {"/api": {      target: "https://xxx.com"},
  },
}複製代碼

router | object/function

router和target有點相似,也是重定向轉發域名的,區別是target只能設置一個string類型的域名,router能夠指定多個域名轉發的映射對象或者函數,而且會覆蓋target

router: {'integration.localhost:3000' : 'http://localhost:8001',  // host only'staging.localhost:3000'     : 'http://localhost:8002',  // host only'localhost:3000/api'         : 'http://localhost:8003',  // host + path'/rest'                      : 'http://localhost:8004'   // path only}router: function(req) {return 'http://localhost:8004';
}複製代碼

pathRewrite | object/function

重寫本地請求的 URL 中的path部分,設置的key字符串會被構形成一個正則表達式來匹配請求的 URL,須要注意的是隻會重寫path部分,前面的host以及後面的queryString都會保留下來和重寫後的域名進行拼接。

devServer: {  proxy: {"/api": {      pathRewrite: {"^/api": "/newApi", // rewrite path  },
    },
  },
}pathRewrite: async function (path, req) {  const should_add_something = await httpRequestToDecideSomething(path);  if (should_add_something) path += "something";  return path;
}複製代碼

changeOrigin | boolean

由於http-proxy-middleware依賴於node-http-proxy實現的,changeOrigin這個參數是從http-proxy中直接拿過來的,找到node-http-proxy的源碼部分,能夠發現以下有關changeOrigin的實現 —— changeOrigin,用到的地方在這裏 —— Request initalization

// requires-port是判斷指定端口在當前協議下是否要求添加在 host 後面,若是是協議默認的端口就不用添加,例如HTTP默認80,會返回falsevar required = require('requires-port');if (options.changeOrigin) {
  outgoing.headers.host =
    required(outgoing.port, options[forward || 'target'].protocol) &&
    !hasPort(outgoing.host)
      ? outgoing.host + ':' + outgoing.port
      : outgoing.host;
}複製代碼

設置request.header.host到底有啥用呢?首先在 HTTP 1.1 的時候要求必須設置這個請求頭參數,由於部分網站的部署是基於域名的部署方案,也就是一個後臺服務器的 IP 地址綁定多個域名,這很容器作到,只須要在域名管理機構的 DNS 解析處添加域名解析規則便可。

基於域名的部署方案取決於支持 HTTP 1.1 的瀏覽器可以在請求域名綁定的 IP 地址的時候發送host這個請求頭參數,以標識當前請求的是什麼域名,否則即便是不一樣域名,服務器接收到的都是相同的 IP 地址,仍然沒法區分。

可是基於域名部署的方案最大問題是難以託管多個 HTTPS 的網站,由於在創建正式的 TCP 鏈接前,須要經過 TCP 進行一段 SSL/TLS 的握手過程,來驗證雙方身份,這邊還沒發送host呢,SSL/TLS 已經開始了。TLS 提供了一種拓展方法 SNI 來保證握手開始前將請求域名發送到服務器,這樣就可讓服務器明確知道對方是誰,發送什麼樣的證書給它。

因此在請求https協議的網站時,必定要配置changeOrigin這個請求頭,否則就會出現如下錯誤:

實踐

好比如今本地我要把知乎專欄《阿里媽媽前端快爆》的內容抓取下來,首先看一下請求是啥,大體是這個地址:

Request URL: https://www.zhihu.com/api/v4/columns/mm-fe/items?limit=10&offset=10複製代碼

那麼我本地webpack的 WDS 能夠這樣配置:

    proxy: {      "/api": {target: "https://www.zhihu.com",changeOrigin: true,pathRewrite: {          "^/api": "/api/v4/columns/mm-fe/items", // rewrite path},
      },
    },複製代碼

請求的地址是/api?limit=10&offset=20:

fetch('/api?limit=10&offset=20')
  .then(function(response) {return response.json();
  })
  .then(function(myJson) {console.log(myJson);
  });複製代碼

這樣就能夠成功轉發請求獲取數據了:

相關文章
相關標籤/搜索