由Content-Length请求头引发的惨案

博客讲述了在生产环境中遇到的客户投诉文件下载慢、超时的问题。经过排查,发现是由于在HTTP请求头中错误地设置了未压缩文件的Content-Length,导致浏览器无法正确判断响应结束,从而引发超时。解决方案是去除Content-Length头或者更新为压缩后的文件大小。文章强调了基础知识的重要性并提供了修复代码示例。

由Content-Length请求头引发的惨案

1、问题描述

​最近生产上频繁收到客户投诉,反馈文件下载响应很慢,而且老是出现等待超时情况,一开始还以为是文件过大或者网络问题导致。经过排查发现问题并非如此简单。
在这里插入图片描述
在这里插入图片描述

2、问题排查定位

​ 首先是根据文件ID查看了文件大小,发现是一张大小约5MB的JPG图片,按道理这么大点图片不会出现一分钟超时。因为文件都是放阿里云OSS的,于是又去排查了一下网络问题,发现也不是。在困扰之际,突然想起来最近对接第三方更改了文件下载接口部分代码,会不会是代码导致,于是翻看了最近改动的代码逻辑,发现出来加了如下代码,并没有其他改动。
在这里插入图片描述
如上图看到只是为了配合上游在请求头加了 “Content-Length”,难道这个会导致客户端无限等待导致超时?怀着疑问去查了相关资料。先看下网上对这个请求头的相关解释。
在这里插入图片描述
看了这个解释后突然明朗了,原来在上传文件的时候会对文件做压缩处理,并且讲上传记录入库,记录文件信息(包含了文件大小,压缩前的)。恰巧代码里添加的Content-Length的文件大小就是从数据库读取的压缩前的文件大小,**这就导致了添加的大小跟实际接口拿到的大小不一致,造成浏览器没法判断响应体已经结束,造成一致pending,直到请求超时。**了解了问题原因,下面就好解决了。

3、问题解决

方法一:

直接去掉Content-Length请求头,简单粗暴。

方法二(推荐):

解决文件大小不一致问题,一是在存储入库的时候就取压缩后的文件大小,而不是取压缩之前。二还可以在不动上传情况下,再添加Content-Length直接从文件中取文件长度,而不是从事先存储的文件大小读取。看下修前前后代码。
在这里插入图片描述

4、总结反馈

至此问题得到解决,总结下还是基础知识不够扎实,还得继续努力。

在 C# 中使用 `HttpWebRequest` 时,`Content-Length` 请求头应填写请求体的字节长度。`Content-Length` 头用于告知服务器客户端发送的数据长度,服务器可以根据这个长度来正确接收和处理请求。 以下是不同情况的示例: #### 1. 发送普通文本数据 当发送普通文本数据时,需要先将文本编码为字节数组,然后获取字节数组的长度作为 `Content-Length` 的值。 ```csharp string content = "这是要发送的文本内容"; byte[] data = Encoding.UTF8.GetBytes(content); HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://example.com"); req.Method = "POST"; req.ContentType = "text/plain; charset=UTF-8"; req.ContentLength = data.Length; using (Stream stream = req.GetRequestStream()) { stream.Write(data, 0, data.Length); } ``` #### 2. 发送 JSON 数据 如果发送的是 JSON 数据,同样先将 JSON 字符串编码为字节数组,再设置 `Content-Length`。 ```csharp string json = "{\"key\": \"value\"}"; byte[] data = Encoding.UTF8.GetBytes(json); HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://example.com"); req.Method = "POST"; req.ContentType = "application/json; charset=UTF-8"; req.ContentLength = data.Length; using (Stream stream = req.GetRequestStream()) { stream.Write(data, 0, data.Length); } ``` #### 3. 发送文件 若要发送文件,需要获取文件的字节长度。 ```csharp string filePath = "path/to/your/file"; FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); long fileLength = fs.Length; HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://example.com"); req.Method = "POST"; req.ContentType = "application/octet-stream"; req.ContentLength = fileLength; using (Stream requestStream = req.GetRequestStream()) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0) { requestStream.Write(buffer, 0, bytesRead); } } fs.Close(); ``` 需要注意的是,如果设置的 `Content-Length` 与实际发送的数据长度不一致,可能会导致服务器接收数据不完整或抛出异常,如 “Bytes to be written to the stream exceed the Content-Length...” 错误[^2]。另外,当使用 `SendChunked` 属性为 `true` 时,不需要设置 `Content-Length`,因为数据将以分块的形式发送[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值