加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

小心 HttpClient 中 FormUrlEncodeContent 的 bug

发布时间:2020-12-16 09:02:33 所属栏目:asp.Net 来源:网络整理
导读:小心 HttpClient 中 FormUrlEncodeContent 的 bug Intro 最近发现活动室预约项目里的上传图片有时候会有问题,周末找时间测试了一下,发现小图片的上传没问题,大图片上传会有问题,而且异常信息还很奇怪, System.UriFormatException: Invalid URI: The Uri

小心 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',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
  • https://github.com/OpenReservation/ReservationServer/commit/0262b2a6ce20c3ec12acc9548235757c18b20690#diff-dd926ccf347a255671a64f9e3edd5a88

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读