webpack dev-server:避免从代理目标返回的 HTTP 错误上出现代理错误
webpack dev-server: Avoid proxy errors on HTTP errors returned from proxy target
我有一个 Vue.js 项目,我在其中配置了一个 webpack 开发服务器来将对 UI 的所有请求代理到我的后端服务器。这是vue.config.js的相关部分:
devServer: {
contentBase: PATHS.build,
port: 9000,
https: false,
hot: true,
progress: true,
inline: true,
watchContentBase: true,
proxy: {
'^/': {
target: 'http://127.0.0.1:8089',
secure: false
},
}
},
我注意到,如果来自 http://127.0.0.1:8089 的 HTTP 响应代码不是 2xx,则代理失败并出现以下错误:
Proxy error: Could not proxy request /api/test from localhost:9000 to http://127.0.0.1:8089.
See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (HPE_INVALID_CHUNK_SIZE).
这也会导致从请求到 localhost:9000 的 HTTP 响应代码对于任何错误都为 500,并且有关服务器端出错的所有信息都将丢失。这是有问题的,因为我希望能够从错误响应中提取信息以显示给用户。
我知道这是可能的,因为我在一个较旧的 Angular 项目上工作,我认为它使用的是 Webpack 3(我现在使用的是 Webpack 4)。我尝试从该项目复制所有开发服务器配置,但它似乎在这里不起作用!
编辑:我错了。代理错误不会发生在每个错误的响应上,而只会发生在一个多部分文件上传的请求上。仍然无法在较小的示例中重现此问题以放在 github 上,尽管如此努力查明原因。
此错误消息来自 node_modules/@vue/cli-service/lib/util/prepareProxy.js
,它为 node-http-proxy
;
定义了一个 onError 回调
所以我做了一些实验,让后端 api 生成 400 404 500 响应,但我没有得到这个错误。
我刚好关闭后台后api,出现错误:
Proxy error: Could not proxy request /hello from localhost:8080 to http://localhost:8081 (ECONNREFUSED).
我在 the doc 中搜索并找到这些:
The error event is emitted if the request to the target fail. We do not do any error handling of messages passed between client and proxy, and messages passed between proxy and target, so it is recommended that you listen on errors and handle them
所以onError
不处理错误代码,只有在请求失败时才调用(500 response
仍然被视为一个完整的请求,connection refuse
不是)
回到你的错误信息,[HPE_INVALID_CHUNK_SIZE]意味着对后端的错误请求api。在this issue中给出了解决方案:add a keep-alive header
:
devServer: {
publicPath: 'http://localhost:9090/front/static-dev/build/',
port: 9090,
proxy: {
'/**': {
target: 'http://localhost:8080',
secure: false,
changeOrigin: true,
headers: {
Connection: 'keep-alive'
}
},
open: true
}
我终于找到问题了,很抱歉,这个问题比我最初写问题时想的要具体得多。
问题与使用 Spring RestTemplate 代理到另一台服务器的请求有关:
例如
@PostMapping("/upload")
public ResponseEntity upload(@RequestParam("file") MultipartFile file)
throws Exception {
String baseUrl = serviceProperties.getAddress();
HttpEntity<MultiValueMap<String, Object>> request = createMultipartRequest(file.getBytes());
return restTemplate.postForEntity(baseUrl + "/api/upload", filterRequest, String.class);
}
当响应不是 200 时,来自其余模板代理的 ResponseEntity returning 包含 header "Connection: close",这会导致连接关闭并导致此请求失败return 任何随后使 dev-server 代理在 UI.
上失败的东西
通过不将来自其余模板代理的响应 header 传递给响应来修复此问题:
@PostMapping("/upload")
public ResponseEntity upload(@RequestParam("file") MultipartFile file)
throws Exception {
String baseUrl = serviceProperties.getAddress();
HttpEntity<MultiValueMap<String, Object>> request = createMultipartRequest(file.getBytes());
ResponseEntity response = restTemplate.postForEntity(baseUrl + "/api/upload", filterRequest, String.class);
return new ResponseEntity<>(response.getBody(), response.getStatusCode());
}
我有一个 Vue.js 项目,我在其中配置了一个 webpack 开发服务器来将对 UI 的所有请求代理到我的后端服务器。这是vue.config.js的相关部分:
devServer: {
contentBase: PATHS.build,
port: 9000,
https: false,
hot: true,
progress: true,
inline: true,
watchContentBase: true,
proxy: {
'^/': {
target: 'http://127.0.0.1:8089',
secure: false
},
}
},
我注意到,如果来自 http://127.0.0.1:8089 的 HTTP 响应代码不是 2xx,则代理失败并出现以下错误:
Proxy error: Could not proxy request /api/test from localhost:9000 to http://127.0.0.1:8089. See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (HPE_INVALID_CHUNK_SIZE).
这也会导致从请求到 localhost:9000 的 HTTP 响应代码对于任何错误都为 500,并且有关服务器端出错的所有信息都将丢失。这是有问题的,因为我希望能够从错误响应中提取信息以显示给用户。
我知道这是可能的,因为我在一个较旧的 Angular 项目上工作,我认为它使用的是 Webpack 3(我现在使用的是 Webpack 4)。我尝试从该项目复制所有开发服务器配置,但它似乎在这里不起作用!
编辑:我错了。代理错误不会发生在每个错误的响应上,而只会发生在一个多部分文件上传的请求上。仍然无法在较小的示例中重现此问题以放在 github 上,尽管如此努力查明原因。
此错误消息来自 node_modules/@vue/cli-service/lib/util/prepareProxy.js
,它为 node-http-proxy
;
所以我做了一些实验,让后端 api 生成 400 404 500 响应,但我没有得到这个错误。
我刚好关闭后台后api,出现错误:
Proxy error: Could not proxy request /hello from localhost:8080 to http://localhost:8081 (ECONNREFUSED).
我在 the doc 中搜索并找到这些:
The error event is emitted if the request to the target fail. We do not do any error handling of messages passed between client and proxy, and messages passed between proxy and target, so it is recommended that you listen on errors and handle them
所以onError
不处理错误代码,只有在请求失败时才调用(500 response
仍然被视为一个完整的请求,connection refuse
不是)
回到你的错误信息,[HPE_INVALID_CHUNK_SIZE]意味着对后端的错误请求api。在this issue中给出了解决方案:add a keep-alive header
:
devServer: {
publicPath: 'http://localhost:9090/front/static-dev/build/',
port: 9090,
proxy: {
'/**': {
target: 'http://localhost:8080',
secure: false,
changeOrigin: true,
headers: {
Connection: 'keep-alive'
}
},
open: true
}
我终于找到问题了,很抱歉,这个问题比我最初写问题时想的要具体得多。
问题与使用 Spring RestTemplate 代理到另一台服务器的请求有关:
例如
@PostMapping("/upload")
public ResponseEntity upload(@RequestParam("file") MultipartFile file)
throws Exception {
String baseUrl = serviceProperties.getAddress();
HttpEntity<MultiValueMap<String, Object>> request = createMultipartRequest(file.getBytes());
return restTemplate.postForEntity(baseUrl + "/api/upload", filterRequest, String.class);
}
当响应不是 200 时,来自其余模板代理的 ResponseEntity returning 包含 header "Connection: close",这会导致连接关闭并导致此请求失败return 任何随后使 dev-server 代理在 UI.
上失败的东西通过不将来自其余模板代理的响应 header 传递给响应来修复此问题:
@PostMapping("/upload")
public ResponseEntity upload(@RequestParam("file") MultipartFile file)
throws Exception {
String baseUrl = serviceProperties.getAddress();
HttpEntity<MultiValueMap<String, Object>> request = createMultipartRequest(file.getBytes());
ResponseEntity response = restTemplate.postForEntity(baseUrl + "/api/upload", filterRequest, String.class);
return new ResponseEntity<>(response.getBody(), response.getStatusCode());
}