项目场景:
由于需要进行前后端联调,而后端因为CORS原因必须解决同源问题,需要前端调整来代理后端流量
问题描述
看到官方文档Proxying API Requests in Development
有写如何配置代理的方案,试过直接在packages.json
中添加proxy键值对,发现不能修改Origin和Host,故而专用setupProxy
方式。但是参考setupProxy
方式操作时不起作用,一直提示404,无法找到对应api。
并且在编译过程提示:
(node:517060) [DEP_WEBPACK_DEV_SERVER_ON_AFTER_SETUP_MIDDLEWARE] DeprecationWarning: 'onAfterSetupMiddleware' option is deprecated. Please use the 'setupMiddlewares' option.
(Use `node --trace-deprecation ...` to show where the warning was created)
(node:517060) [DEP_WEBPACK_DEV_SERVER_ON_BEFORE_SETUP_MIDDLEWARE] DeprecationWarning: 'onBeforeSetupMiddleware' option is deprecated. Please use the 'setupMiddlewares' option.
前置说明
项目使用TypeScript开发,以下为相关组件版本
- node版本v18.15.0
- npm版本9.5.0
- 依赖项版本如下:
{ 'dependencies': { ... "http-proxy-middleware": "^3.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", } }
网上见到的处理办法包括但不限于
-
版本过低,
react-scripts
低于2.0.0
时需要修改createProxy.js代码
从const proxy = require('http-proxy-middleware') module.exports = function(app) { app.use( proxy('/api1', { //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000) target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址) changeOrigin: true, //控制服务器接收到的请求头中host字段的值 pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置) }), proxy('/api2', { target: 'http://localhost:5001', changeOrigin: true, pathRewrite: {'^/api2': ''} }) ) }
修改为
const { createProxyMiddleware } = require("http-proxy-middleware") module.exports = function (app) { app.use( createProxyMiddleware("/api1",{ target: "http://localhost:5000", //配置转发目标地址(能返回数据的服务器地址) changeOrigin: true, //控制服务器接收到的请求头中host字段的值 pathRewrite: { "^/api1": "" }, }), createProxyMiddleware("/api2",{ target: "http://localhost:5001", //配置转发目标地址(能返回数据的服务器地址) changeOrigin: true, //控制服务器接收到的请求头中host字段的值 pathRewrite: { "^/api2": "" }, }) ) }
https://github.com/facebook/create-react-app/issues/11860
-
修改
create-react-app
版本 -
直接修改
node-modules
下的react-script
源码,将node_modules/react-scripts/config/webpackDevServer.config.js
中的onBeforeSetupMiddleware
修改为setupMiddlewares
从onBeforeSetupMiddleware(devServer) { // Keep `evalSourceMapMiddleware` // middlewares before `redirectServedPath` otherwise will not have any effect // This lets us fetch source contents from webpack for the error overlay devServer.app.use(evalSourceMapMiddleware(devServer)); if (fs.existsSync(paths.proxySetup)) { // This registers user provided middleware for proxy reasons require(paths.proxySetup)(devServer.app); } }, onAfterSetupMiddleware(devServer) { // Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match devServer.app.use(redirectServedPath(paths.publicUrlOrPath)); // This service worker file is effectively a 'no-op' that will reset any // previous service worker registered for the same host:port combination. // We do this in development to avoid hitting the production cache if // it used the same host and port. // https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432 devServer.app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath)); },
改为
setupMiddlewares: (middlewares, devServer) => { if (!devServer) { throw new Error('webpack-dev-server is not defined') } if (fs.existsSync(paths.proxySetup)) { require(paths.proxySetup)(devServer.app) } middlewares.push( evalSourceMapMiddleware(devServer), redirectServedPath(paths.publicUrlOrPath), noopServiceWorkerMiddleware(paths.publicUrlOrPath) ) return middlewares; },
上述方法均不起作用,且无法看到错误信息
排查及处置:
根据源码和编译前webpack的报错提示
(node:517060) [DEP_WEBPACK_DEV_SERVER_ON_AFTER_SETUP_MIDDLEWARE] DeprecationWarning: 'onAfterSetupMiddleware' option is deprecated. Please use the 'setupMiddlewares' option.
(Use `node --trace-deprecation ...` to show where the warning was created)
(node:517060) [DEP_WEBPACK_DEV_SERVER_ON_BEFORE_SETUP_MIDDLEWARE] DeprecationWarning: 'onBeforeSetupMiddleware' option is deprecated. Please use the 'setupMiddlewares' option.
我们找到源码位置,在项目node_modules/react-scripts/config/webpackDevServer.config.js
文件中,参考导出函数onBeforeSetupMiddleware
的内容,我们在其内部下断点,输出paths.proxySetup
,并且捕获require(paths.proxySetup)(devServer.app);
产生的异常。根据这一方法进行检查,发现paths.proxySetup
只解析src/setupProxy.js
不解析src/setupProxy.ts
,需要修改代码文件名及内部代码规范。
而后根据后端响应的路由信息,检查到代理需要提供后缀或者对路径进行rewrite,
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target : 'http://localhost:8080/api',
changeOrigin: true,
})
);
};
将/api
添加到target
对应后端地址的路径上即可解决404问题。
总结
- 使用
setupProxy.js
文件名 - 注意代理路径问题,可以联合后端响应一起调试