Peeling off the cocoon: Detailing the detailed troubleshooting process of an invalid DevServer Proxy configuration problem

The cause of the matter is this. In an online project, one of the interfaces containing login and menu acquisition took a long time to respond. The backend asked me to try a new interface under another domain name that was not forwarded by the service. The old interface Cross-domain requests are allowed, but the new interface does not allow local access (only domain name access for release testing/production is allowed).

question

So the question is, how can the local environment successfully access the new interface and verify whether the business functions are effective?

Try the process

I first thought of configuring the devServer directly in the webpack project and modifying the interface address (for security and privacy, the company’s actual domain name is hidden and replaced with xxxxx.)

devServer: {
  proxy: {
    '/': {
      target: 'https://xxxxx.cn',
      pathRewrite: {
        '/proxyApi': '',
      },
      changeOrigin: true,
    },
  },
} 

But the returned interface prompts [Invalid login status], at least it is not cross-domain! I originally thought that the proxy had been successful, I just needed to find the backend and see the error report.

But the backend reported this error because the request header did not carry the specified parameters, and it could not find the detailed information of the request. At this time, I started to have doubts again. It was clear that there was a request header.

doubt

The request address seen on the Chrome browser is not the real interface request address provided by the backend, but the field with my proxy added. In the response body, I did not find the location and other fields fed back to the real request interface.

At this time, I wonder, is the proxy really effective? Is the interface I requested a real back-end interface? Start to verify whether the proxy of devServer is executed. After configuring the function for output before and after the request at the proxy, it was found that neither onProxyReq nor onProxyRes was executed.

proxy : {
   '/proxyApi' : {
     target : 'https://xxxxx.cn' ,
     pathRewrite : {
       '/proxyApi' : '' , 
    }, changeOrigin : true ,
     onProxyReq ( proxyReq, req, res ) {
       console . log ( '>>>Request' , req); 
    }, onProxyRes ( proxyRes, req, res ) {
       //Response hook function console . log ( '>>>Response' , res); 
    }, 
  }, 
},
    
    
      

So at this time, I guess it is that the entire devServer is not effective, but how to prove that it is not effective?

Confirm

At present, the proxy backend domain name is not under our control. I have no way of knowing whether it is sent to the backend server, so I plan to use nodejs to open a service myself. The way to open the service is very simple. It can be done with a few lines of code using the core module https.

const http = require("http");

const server = http.createServer((req, res) => {
  console.log(">>req", req.url, req.rawHeaders );
  res.end("hello");
});

server.listen("3002", () => {
  console.log("3002端口启动了");
});

After starting the service through node, first verify whether the request can be intercepted and enter it directly through the browser window

Alas~ The service is started, the page also gets a response, and the server can obtain the data just requested by get.

At this time, change the proxy configuration in the project to the service of port 3002, execute the business logic code again to send the request, and find that the service console started on port 3002 is empty! That is, it did not intercept the request at all.

proxy: {
  '/proxyApi': {
    target: 'http://localhost:3002',
},

I guessed it was because of the interface request tool in the project that it could not be intercepted, so I used fetch directly on the page to send the request. At this time, I found that the service on port 3002 still did not receive the request.

fetch('https://xxxxx.cn/proxyApi/yyyyy/operateTargetNew')

I originally thought it was a problem with proxy character matching, because the /proxyApi logo appears in the middle of the entire URL. I tried to change it to the regular expression ” */proxyApi/ “, but it was also invalid.

proxy: {
  '**/proxyApi/*': {
},

try again

At this time, I realized a problem. It seems that the interface with domain name cannot be accessed. What if I just remove the domain name?

At this time, use fetch directly to request the interface address that does not contain the domain name.

fetch('/proxyApi/yyyyy/operateTargetNew')

At this time, I finally saw the dawn that the problem was about to be solved! The call interface successfully obtained the response returned by port 3002.

The request details can also be obtained on the local 3002 port service.

Clear away the clouds

After querying the data, I found that it was indeed the interface address. The proxy configuration of Webpack DevServer is mainly used in the development environment , targeting API requests issued by the local DevServer.

When you send requests in front-end code, you usually use relative paths (such as /api/xxx/yyy) so that they are sent to the host and port of the current page, which is the Webpack DevServer.

At this time, DevServer’s proxy settings can forward the request to the configured backend server.

// webpack.config.js
module.exports = {
  // ...
  devServer: {
    proxy: {
      '/api': {
        target: 'http://your-backend-server.com',
        changeOrigin: true,
      },
    },
  },
};

Now, if you send a request to /api/xxx/yyy, DevServer will proxy it to http://your-backend-server.com/api/xxx/yyy .

However, if you use the full URL directly in the front-end code (that is, including the domain name https://www.xxxx.com/api/xxx/yyy ), the Webpack DevServer is bypassed and the request is sent directly to the full URL corresponding server. DevServer’s proxy configuration will not interact with this request and therefore cannot proxy it to the target server you configured.

request modification

So I changed back to the interface that requires proxying, and made some changes to the project logic. Because the default network library will splice URLs, I made a judgment here and saved the domain name that needs proxying and the characters of the proxy as a set of values.

If the match requires a proxy requirement, replace it with the prefix.

// In the local environment, you need to remove the domain name from the proxy interface and splice the proxy prefix 
  if (process. env . NODE_ENV === 'development' ) {
     const proxyObj = {
       'https://xxxx.cn' : '/proxyApi' , 
    }; const proxyKeys = Object . keys (proxyObj);
     for ( let i = 0 ; i < proxyKeys. length ; i++) {
       const host = proxyKeys[i];
       if (option. url . includes (host)) {
         const prefix = proxyObj[host]; 
        option. url = option. url . replace (host, prefix); 
      } 
    } 
  }
    

In this way, the interface request can be spliced ​​into the https://xxxx.con domain name and replaced with the specified prefix, so that this part of the request will go through the proxy.

I am very ashamed. Although I have known for a long time that webpack’s proxy configuration solves local cross-domain problems, I rarely configure it myself. Usually the backend solves the cross-domain problem or the project has its own solution, so I really configure it myself. I was a little confused at the time.