zoukankan      html  css  js  c++  java
  • 使用 HttpClient 进行表单提交时,遇到的问题

    问题

    在开发微信支付的小微商户进件接口时,需要通过表单来上传身份证图片等数据。在微信支付接口文档也说明了,需要使用 multipart/form-data 的方式发送请求。.NET 提供了 MultipartFormDataContent 类型,帮助我们构建表单请求,故有以下代码:

    var form = new MultipartFormDataContent()
    {
        {new StringContent("Value"),"Name},
        {new ByteArrayContent(new byte[]{}/*模拟文件数据*/),"File,"FileName}
    }
    

    按照微信支付官方文档提交之后,一直提示参数错误,百思不得其解。

    原因

    通过 Postman 模拟表单提交,捕获数据包,将其与 C# 的提交代码进行对比,发现了两处问题。

    Postman 的原始提交:

    POST http://api.mch.weixin.qq.com/secapi/mch/uploadmedia HTTP/1.1
    User-Agent: PostmanRuntime/7.21.0
    Accept: */*
    Cache-Control: no-cache
    Postman-Token: b6800c0f-3f16-4981-b661-e6d16fc1bb1e
    Host: api.mch.weixin.qq.com
    Content-Type: multipart/form-data; boundary=--------------------------639275760242036520206377
    Accept-Encoding: gzip, deflate
    Content-Length: 566
    Connection: keep-alive
    
    ----------------------------639275760242036520206377
    Content-Disposition: form-data; name="mch_id"
    
    1565111111
    ----------------------------639275760242036520206377
    Content-Disposition: form-data; name="media_hash"
    
    7215E92A8F3F3D0256484EFFF53A25F6
    ----------------------------639275760242036520206377
    Content-Disposition: form-data; name="sign_type"
    
    HMAC-SHA256
    ----------------------------639275760242036520206377
    Content-Disposition: form-data; name="sign"
    
    A1D8B094FA24BE5531D1AC198DE25550
    ----------------------------639275760242036520206377--
    

    C# 代码的提交:

    POST http://api.mch.weixin.qq.com/secapi/mch/uploadmedia HTTP/1.1
    Host: api.mch.weixin.qq.com
    Content-Type: multipart/form-data; boundary="e9d5712f-7923-4ec5-8bf3-c8d5d3cd3217"
    Content-Length: 502
    
    --e9d5712f-7923-4ec5-8bf3-c8d5d3cd3217
    Content-Type: text/plain; charset=utf-8
    Content-Disposition: form-data; name=mch_id
    
    
    --e9d5712f-7923-4ec5-8bf3-c8d5d3cd3217
    Content-Type: text/plain; charset=utf-8
    Content-Disposition: form-data; name=media_hash
    
    33F15BC2D17D6FFBC18FA566EF65722E
    --e9d5712f-7923-4ec5-8bf3-c8d5d3cd3217
    Content-Type: text/plain; charset=utf-8
    Content-Disposition: form-data; name=sign
    
    1E377684F9BD583D2ED26FB367916C0C
    --e9d5712f-7923-4ec5-8bf3-c8d5d3cd3217--
    

    1. Boundary 的双引号

    使用 MultipartFormDataContent 提交的表单请求,外部 Content-Typeboundary 值带有 " 号。而 Postman 提交的表单请求,它的 boudary 值是没有双引号的。

    那为什么会造成这样的差异呢?参考 这篇 博客的讲解,是由于各个系统/语言针对 RFC 2046 的实现不一致导致的。针对于 MultipartFormDataContent 的行为,如果 Boundary 后面的值带有双引号是符合标准的。

    RFC 2612 原文:

    1. Although RFC 2046 [40] permits the boundary string to be
      quoted, some existing implementations handle a quoted boundary
      string incorrectly.

    Boundary 的作用,是一个随机生成的字符串,在 HTTP 协议当中用于分割内部多个 Content。为什么是随机生成的呢?就是防止这个分割符跟你内部的 Content 产生重复造成意外。(C# 默认使用的是 Guid 作为随机串,你也可以在构造 MultipartFormDataContent 的时候,通过其构造函数手动指定)

    2. 表单内键值对,值的双引号

    第二个问题则是表单内的内容,他们的 name 键值对,其值又没有双引号,所以你得在添加 Content 的时候,得手动指定双引号。

    解决

    两个问题都是由于双引号导致的,所以只需要在真正发起调用之前将内部的双引号替换为空,或者将缺失的双引号添加上即可。

    针对问题一,其内部的 ContentType.Parameters ,通过 LINQ 找到 boundary 的键值对,替换内部的双引号即可。

    var boundaryValue = form.Headers.ContentType.Parameters.Single(p => p.Name == "boundary");
    boundaryValue.Value = boundaryValue.Value.Replace(""", String.Empty);
    

    针对问题二,在构造内部 Content 的时候,其 Name 手动赋予双引号。

    var form = new MultipartFormDataContent
    {
        {new StringContent(mchId), ""mch_id""},
        {new ByteArrayContent(bytes), "media", $""{HttpUtility.UrlEncode(Path.GetFileName(imagePath))}""},
        {new StringContent(mediaHash), ""media_hash""},
        {new StringContent(sign), "sign"}
    };
    
  • 相关阅读:
    魅族手机不能通过设置Style和Background展示透明Activity的解决方法
    [翻译]The dark side of AsyncTask
    Eclipse卡死在Building workspace和android library update解决方法
    影响Java代码性能的一些细节
    WebView通过loadDataWithBaseURL加载本地页面卡死
    [04] Android逐帧动画(一)
    [03] Android系统亮度调节
    iOS UIViewContentMode详解
    setObject:forKey:与setValue:forKey:的区别
    选择排序
  • 原文地址:https://www.cnblogs.com/myzony/p/12114507.html
Copyright © 2011-2022 走看看