While the previous article briefly introduced the following use of WDS within WebPack, this section discusses how to configure proxy within WDS.

devServer

Webpack-devserver, commonly referred to as WDS, is a server configuration built into WebPack for the development environment. Webpack itself provides three ways for the development environment to automatically compile code after modification to improve development efficiency:

  • Observation model

  • WDS

  • webpack-dev-middleware

In general, WDS is the easiest to configure and provides HMR functionality. Simply configure devServer.hot: true to enable it. Let’s focus on proxy configuration for WDS.

http-proxy-middleware

Webpack’s built-in proxy function for WDS comes from http-proxy-Middleware, a third party tool. As I’ve read before, the most important thing about open source is not to contribute your own code, but to take someone else’s code and use it. From the perspective of the open source community, this is really the core. Only when open source drives open source can the community atmosphere be better.

Without further ado, let’s take a look at the configuration of HTTP-proxy-Middleware.

configuration

URL

Before we get into the details of the configuration, let’s review the composition of URLS under the HTTP protocol:

Http-proxy-middleware itself combines some of the configurations of HTTP-proxy, but the document configuration is abstract and most of the configurations are not used in real development. Here are a few important properties.

target | string

Target specifies the target domain name to be forwarded by the proxy. In WDS, you can set it as follows: when a local request is sent to localhost:3000/ API, the WDS will forward the request to https://xxx.com/api

devServer: {
  proxy: {
    "/api": {
      target: "https://xxx.com"}},}Copy the code

router | object/function

A router is similar to a target in that it redirects and forwards domain names. The difference is that target can only be set to a string domain name. A router can specify mapping objects or functions for multiple domain names and overrides the 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';
}
Copy the code

pathRewrite | object/function

Rewrite the path part of the local request URL. The set key string will be constructed into a regular expression to match the requested URL. Note that only the path part will be overwritten, and the preceding host and the following queryString will be preserved and merged with the rewritten domain name.

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;
}
Copy the code

changeOrigin | boolean

Because HTTP-proxy-Middleware relies on a Node-http-proxy implementation, the changeOrigin parameter is taken directly from http-proxy. Find the source code for Node-http-proxy. You can find the following implementation of changeOrigin — changeOrigin, which is used here — Request initalization

// requires-port specifies whether the specified port is required to be added after host in the current protocol. If the port is the default protocol port, false is returned, for example, HTTP default port 80
var 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;
}
Copy the code

What is the use of setting request.header.host? First of all, HTTP 1.1 requires that this request header parameter must be set, because some websites are deployed based on the domain name deployment solution, that is, the IP address of a background server is bound to multiple domain names, which can be easily done, just need to add domain name resolution rules in the DNS resolution office of the domain name management agency.

The domain-based deployment scheme depends on HTTP 1.1-enabled browsers being able to send the host header parameter when requesting an IP address bound to the domain name to identify the requested domain name. Otherwise, the server will receive the same IP address even if the domain name is different.

However, the biggest problem with domain-based deployment is that it is difficult to host multiple HTTPS sites, because before establishing a formal TCP connection, an SSL/TLS handshake is required over TCP to verify the identity of both parties. TLS provides an extended SNI method to ensure that the requested domain name is sent to the server before the handshake begins, so that the server knows exactly who the other party is and what certificate to send to it.

Therefore, when requesting HTTPS websites, you must configure the changeOrigin request header. Otherwise, the following error occurs:

practice

For example, now I want to grab the content of zhihu column “Ali mother front end quick explosion”, first look at the request is what, generally this address:

Request URL: https://www.zhihu.com/api/v4/columns/mm-fe/items?limit=10&offset=10
Copy the code

So my local Webpack WDS can be configured like this:

    proxy: {
      "/api": {
        target: "https://www.zhihu.com".changeOrigin: true.pathRewrite: {
          "^/api": "/api/v4/columns/mm-fe/items".// rewrite path}},},Copy the code

The requested address is/API? Limit = 10 & offset = 20:

fetch('/api? limit=10&offset=20')
  .then(function(response) {
    return response.json();
  })
  .then(function(myJson) {
    console.log(myJson);
  });
Copy the code

Then the request can be successfully forwarded to fetch data: