如何用webpack-dev-server重写同域请求路径?遇ETIMEDOUT问题
Webpack-dev-server 代理URL重写异常排查
问题背景
需求是通过webpack-dev-server将匹配/**/locales/**/*.json的请求URL重写,例如把some.domain.com/subpath/locales/another/file.json改写为some.domain.com/locales/file.json。
此前配置正常,代码迁移后先后出现EHOSTUNREACH和ETIMEDOUT错误,错误日志:
<e> [webpack-dev-server] [HPM] Error occurred while proxying request some.domain.com/locales/file.json to https://some.domain.com/ [ETIMEDOUT] (https://nodejs.org/api/errors.html#errors_common_system_errors)
已通过hosts文件解析some.domain.com,当前配置代码如下:
const HOST_DOMAIN = 'some.domain.com' return { devServer: { server: { type: "https" }, port: 443, compress: true, allowedHosts: "all", headers: { "Access-Control-Allow-Origin": "*", }, client: { webSocketURL: `auto://${HOST_DOMAIN}/ws`, }, proxy: { '/**/locales/**/*.json': { target: 'https://' + HOST_DOMAIN, pathRewrite: function (path) { const parts = path.split('/'); return '/locales/' + parts.pop(); }, secure: false } }, static: [ { directory: path.join(__dirname, "src/locales"), publicPath: `/locales`, }, ], }, // ... }
已尝试设置originRewrite: true但无效,需确认:
- 该URL重写需求是否可行
- 当前配置是否正确
- 异常的原因
解答
1. 需求完全可行
webpack-dev-server的代理功能底层依赖http-proxy-middleware,支持复杂路径匹配和自定义重写逻辑,你要实现的URL重写需求完全可以做到。
2. 当前配置的问题
- 路径匹配规则有歧义:
/**/locales/**/*.json这种glob匹配写法可能导致部分请求被错误拦截,或者匹配优先级出问题,不如正则表达式精确。 - 代理循环是核心隐患:你的dev-server运行在
some.domain.com:443,代理目标又是https://some.domain.com,加上hosts把这个域名指向本地,请求被代理后会直接打回本地dev-server,形成循环请求,最终就会出现超时或无法连接的错误。 - static配置和代理冲突:static里把
src/locales映射到/locales,当代理后的请求到/locales/file.json时,会优先读取本地静态文件,而不是转发到目标服务器,逻辑上会混乱。 - pathRewrite逻辑虽能工作但不够健壮:
path.split('/').pop()虽然能拿到最后一段文件名,但如果路径里有空字符串(比如开头的/),可能会出现意外情况,不过这不是当前报错的原因。
3. 失效原因
代码迁移后,要么是hosts配置变了(把域名指向了本地),要么是dev-server端口改成了443,或者依赖版本更新后http-proxy-middleware的匹配逻辑变了,这些都触发了代理循环的问题。之前配置正常,大概率是当时没有形成这种循环(比如dev-server用的是其他端口,或者hosts没指向本地)。
修正方案
首先解决代理循环问题(最关键)
有两种方式:
- 改dev-server端口:把端口从443改成8443这类非标准HTTPS端口,同时调整webSocketURL:
port: 8443, client: { webSocketURL: `auto://${HOST_DOMAIN}:8443/ws`, }, - 绕开hosts解析:保持443端口,但代理目标直接用服务器真实IP,同时设置
changeOrigin和Host头:target: 'https://目标服务器真实IP', changeOrigin: true, headers: { Host: HOST_DOMAIN }
优化路径匹配与重写
把glob匹配改成正则,更精确:
proxy: { '^/.*/locales/.*/.*\\.json$': { // 匹配任意前缀 + locales + 任意层级 + .json后缀的路径 target: 'https://' + HOST_DOMAIN, pathRewrite: (path) => { // 提取文件名,重写成/locales/文件名.json const match = path.match(/([^/]+)\.json$/); return match ? `/locales/${match[1]}.json` : path; }, secure: false, changeOrigin: true } }
解决static和代理的冲突
如果不需要本地静态资源优先响应,给代理加bypass逻辑跳过static:
proxy: { '^/.*/locales/.*/.*\\.json$': { // ...其他配置 bypass: () => false // 直接走代理,不触发static资源 } }
内容的提问来源于stack exchange,提问作者ricardo-dlc
相关产品推荐
相关产品推荐

