数据传到一半没有了

3,939 阅读3分钟

问题描述

vue-cli3 构建的项目,本地开发环境通过 webpack中 的 devserver 代理请求到后端服务,其他接口均正常,只有接口A是500,返回数据错误:

Proxy error: Could not proxy request /xxx/list?pageNo=1&pageSize=10 from localhost:8080 to http://x.x.x.x:8108 (ECONNRESET).

{"code":"200","msg":"请求成功","success":true,"data":{"total":107,"list":[{...},...,{"id":132,..."name":"账户�Proxy error: Could not proxy request /eventNotifyPerson/list?pageNo=1&pageSize=10 from localhost:8080 to http://172.16.21.237:8108 (ECONNRESET).

查看Node.js Error中详细解释:

ECONNRESET (Connection reset by peer): A connection was forcibly closed by a peer. This normally results from a loss of the connection on the remote socket due to a timeout or reboot. Commonly encountered via the http and net modules.

排查过程

1. 是否是接口问题

通过浏览器 url 直接访问后端服务接口A,接口返回200,是可以拿到全部数据的。

2. 确定是否数据有异常

让后端在数据库里删掉id为132的这条数据,发现问题仍然存在;

3. 确定是否前端代理有问题

后端将程序发布到dev环境,前端代理不变,接口返回200,数据正常。

4. 抓包排查

wireshark抓包发现http传输,数据包没传输完,连接就断开了。

解决过程

尝试在前端请求头中加Connection: Keep-Alive

一开始尝试在axios请求中加,添加方式如下:

axios.defaults.headers['Connection'] = 'Keep-Alive'

控制台报错:

换另外一种方式:
浏览器看到是:Connection: Keep-Alive
但抓包中显示:connection: close,难道是加的不对,没生效?又参考axios的api文档,在接口的config中添加,结果还是一样。
查找资料HTTP Keep-Alive模式,发现浏览器keep-alive机制如下:
查看抓包中的http请求是1.1版本,理应会是默认开启keep-alive的。原来虽然浏览器发出的时候,keep-alive是默认开启的,但经过webpack的代理转发,keep-alive被关闭了,代理将这个值设置为了close。

随后查找资料,深入分析vue的webpack代理设置:vue.config.js中的devServer.proxy实际使用的是http-proxy-middleware中间件,查看配置项,修改devServer如下:

查看wireshark抓包内容,确认proxy的Connection: Keep-Alive,添加成功。
再次访问后端接口,接口200,数据正常,问题修复。

反思

  • 初步结论:浏览器会默认开启keep-alive,所以通过浏览器url访问可以拿到全部数据,但是经过webpack的代理转发,keep-alive被关掉了,要在这里设置开启。在接口返回数据量很大的时候,会遇到这种问题。
  • 问题反思:虽然这样接口正常了,但是在开发其他项目的时候,数据量有比这个更大的,在proxy中从来没有加过keep-alive。
  • 再次确认是否是后端问题:后端把服务部署到本地的tomcat下,前端代理不加keep-alive,接口返回200,数据正常。
  • 最终结论:原来后端服务是部署在jetty下,dev环境是部署在tomcat下(听后端专家说:jetty提供的数据包保存在内存中,发送给前端,包还没发完,就被jetty给关掉了,导致抓包中数据丢失;而tomcat会保证数据数据全部发送给前端,所以dev环境正常),所以会出现访问后端本地,接口500,访问dev环境接口200,最终确认是后端jetty配置问题导致。