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);
  });复制代码

这样就能够成功转发请求获取数据了:

相关文章
相关标签/搜索