小心 HttpClient 中的 FormUrlEncodeContent 的 bug

Intro

最近发现活动室预约项目里的上传图片有时候会有问题,周末找时间测试了一下,发现小图片的上传没问题,大图片上传会有问题,而且异常信息还很奇怪,System.UriFormatException: Invalid URI: The Uri string is too long 看这个错误的信息还以为是请求的 url 过长导致的,但是实际请求的 url 很短,诡异的异常信息

测试示例

为了方便大家了解和测试这个bug,我在 Github 上提供了一个示例 https://github.com/WeihanLi/SamplesInPractice/blob/master/HttpClientTest/FormUrlEncodeContentTest.cs

HttpClient 示例代码:

public class FormUrlEncodeContentTest
{private const string TestUrl = "https://cnblogs.com";public static async Task FormUrlEncodedContentLengthTest(){using (var httpClient = new HttpClient(new NoProxyHttpClientHandler())){using (var response = await httpClient.PostAsync(TestUrl, new FormUrlEncodedContent(new Dictionary<string, string>(){{"bigContent", new string('a', 65535)},}))){Console.WriteLine($"response status code:{response.StatusCode}");}}}public static async Task ByteArrayContentLengthTest(){using (var httpClient = new HttpClient(new NoProxyHttpClientHandler())){var postContent = $"bigContent={new string('a', 65535)}";using (var response = await httpClient.PostAsync(TestUrl, new ByteArrayContent(postContent.GetBytes()))){Console.WriteLine($"response status code:{response.StatusCode}");}}}public static async Task StringContentLengthTest(){using (var httpClient = new HttpClient(new NoProxyHttpClientHandler())){var postContent = $"bigContent={new string('a', 65535)}";using (var response = await httpClient.PostAsync(TestUrl, new StringContent(postContent))){Console.WriteLine($"response status code:{response.StatusCode}");}}}
}

测试代码:

InvokeHelper.OnInvokeException = Console.WriteLine;await InvokeHelper.TryInvokeAsync(FormUrlEncodeContentTest.FormUrlEncodedContentLengthTest);
Console.WriteLine();
await InvokeHelper.TryInvokeAsync(FormUrlEncodeContentTest.StringContentLengthTest);
Console.WriteLine();
await InvokeHelper.TryInvokeAsync(FormUrlEncodeContentTest.ByteArrayContentLengthTest);Console.WriteLine("Completed!");

输出结果如下:

揪出异常始末

上传图片的时候会调用一个码云的一个 POST 接口来保存上传的图片,参数是通过 form-data 的方式传递的,在 POST 的时候报异常了,异常信息很诡异,具体信息和上面的是一样的:

这个异常信息看上去像是 url 过长导致的,但是实际的 url 很短只有几百,而且从调用的堆栈上来看是 FormUrlEncodedContent 的 bug,然后根据异常堆栈信息去看了一下源码,部分源码如下:

首先看 FormUrlEncodedContent 做了什么:

然后再找上一层堆栈信息,Uri是一个分部类(partial),你如果直接在 Github 上 Find 的话会找到多个 Uri 相关的文件,最后在 UriExt 中找到了上面的 EscapeDataString 方法:

最后来看最上层的堆栈信息 UriHelper.EsacpeString 方法,找到异常抛出的地方

在 Uri 这个类中可以找到上面定义的 c_MaxUriBufferSize,它的值是 0xFFF0 转成十进制就是 65520

找到问题所在之后,就可以避免这个问题了,再遇到这个问题也就知道是怎么回事了,上面的问题就是 post 的数据太大了,超过了这个限制,所以引发的异常

More

既然知道这个是 FormUrlEncodedContent 的 bug,那么修复它就可以通过避免使用它,可以直接使用 ByteArray Content,或者不需要 Encode 处理直接用 StringContent 也是可以的

后来在 Github 搜 issue 的时候发现也有很多人遇到了这个问题,这个问题会在 net5 中得到修复,详见 PR https://github.com/dotnet/corefx/pull/41686

文中一些源码的链接在文章最后的 Reference 的部分可以找到

Reference

  • https://github.com/dotnet/corefx/blob/release/3.1/src/System.Net.Http/src/System/Net/Http/FormUrlEncodedContent.cs#L53

  • https://github.com/dotnet/corefx/blob/release/3.1/src/System.Private.Uri/src/System/UriExt.cs#L597

  • https://github.com/dotnet/corefx/blob/release/3.1/src/System.Private.Uri/src/System/UriHelper.cs#L134

  • https://github.com/dotnet/corefx/blob/release/3.1/src/System.Private.Uri/src/System/Uri.cs

  • https://github.com/dotnet/corefx/pull/41686

  • https://github.com/dotnet/corefx/tree/release/3.1

  • https://github.com/WeihanLi/SamplesInPractice/blob/master/HttpClientTest/Program.cs

小心 HttpClient 中的 FormUrlEncodeContent 的 bug相关推荐

  1. java string 占位符_驳《阿里「Java开发手册」中的1个bug》?

    前两天写了一篇关于<阿里Java开发手册中的 1 个bug>的文章,评论区有点炸锅了,基本分为两派,支持老王的和质疑老王的. 首先来说,无论是那一方,我都真诚的感谢你们.特别是「二师兄」, ...

  2. (用微信扫的静态链接二维码)微信native支付模式官方提供的demo文件中的几个bug修正...

    原文:(用微信扫的静态链接二维码)微信native支付模式官方提供的demo文件中的几个bug修正 native支付模式一demo(用微信扫的静态链接二维码)BUG修复,一共4个BUG 1.nativ ...

  3. OpenCV中initUndistortRectifyMap函数存在bug原因探究

    原文首发于公众号「3D视觉工坊」:OpenCV中initUndistortRectifyMap函数存在bug原因探究. 最近在运行如下一段代码时,生成的mapx和mapy有点异常. 代码片段如下: # ...

  4. UNITY 中List.Sort的BUG

    UNITY 中List.Sort的BUG List<int> lst = new List<int>();lst.Add(202);lst.Add(20);lst.Add(40 ...

  5. 驳《阿里「Java开发手册」中的1个bug》?

    这是我的第 211 期分享 作者 | 王磊 来源 | Java中文社群(ID:javacn666) 转载请联系授权(微信ID:GG_Stone) 前两天写了一篇关于<阿里Java开发手册中的 1 ...

  6. go 怎么等待所有的协程完成_理解真实世界中 Go 的并发 BUG

    点击上方蓝色"Go语言中文网"关注,回复「电子书」领全套Go资料 有几个学生研究归纳了go编程中的并发bugs,发表了一篇(英文)论文:<Understanding Real ...

  7. 解决iframe在ios中无法滚动的bug

    https://fly.layui.com/jie/32020/(无效) 修改方法: 1.在嵌入进iframe的每个页面的<body>里面加个id,如<body id="i ...

  8. 5006.c++类中使用static变量bug

    c++类中使用static变量bug 正常情况,一般c++类中,不能使用static 定义成员,一般情况下在定义时编译器会进行报错.我呢由于c语言的使用习惯,没有太注意.在c++类的方法中,写代码时顺 ...

  9. 2021年C++项目中的十大Bug:乍一看都正确的代码,实则暗藏玄机

    作者 | Vladislav Stolyarov 译者 | 弯月 出品 | CSDN(ID:CSDNnews) 在程序员的新年祝福中,大家或多或少会来一句,新年编码无Bug.Bug越写越少--对程序员 ...

最新文章

  1. Vmware Workstation VMX 在资源管理器中杀不掉(虚拟机繁忙导致无法关机)
  2. 清华特奖答辩前10出炉,两名CS学生3篇顶会一作,有人周读3000页英文论文!
  3. Linq之延迟加载特性
  4. 优化器 - tf.keras.optimizers.SGD()【TensorFlow2入门手册】
  5. Hadoop YARN安装部署初探
  6. 直接管理内存——new和delete
  7. Python实现遍历目录与子目录,并找到以.txt结尾的文件
  8. 搭建samba文件共享服务
  9. 怎么运行Typescript
  10. python字频统计软件_python结巴分词以及词频统计实例
  11. html 长文本 截断 jquery 扩展脚本
  12. C++ 形参与实参的传递
  13. 使用samba完成Linux服务器与Windows之间的映射
  14. java composite 模式_《JAVA设计模式》中的组合模式Composite
  15. Dxg——C++ 开发笔记整理分类合集【所有的相关记录,都整理在此】
  16. len函数实例python_Python通过len函数返回对象长度
  17. MASK RCNN在tensorflow 2.5中运行
  18. HTML中背景图片如何自适应屏幕
  19. 当8081端口被占用了怎么办?
  20. 腾讯市值首破5000亿美元;阿里224亿港币入股高鑫零售;特斯拉新超跑在华接受预定丨价值早报

热门文章

  1. BZOJ 4516: [Sdoi2016]生成魔咒 [后缀自动机]
  2. listview嵌套gridview
  3. linux最常用的20条命令
  4. shell编程的一些例子4
  5. chromebook刷机_如何在Chromebook上拍照
  6. 编写iptables脚本实现IP地址、端口过滤
  7. 微信支付四大支付模式分别有哪些区别?
  8. MongoDB基本操作(增删改查)
  9. nat+端口转发,使得宿主机secureCRT可以访问vbox里linux虚拟机
  10. linux 学习笔记 显示压缩文件 gong.zip 的文件内容