使用 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-Type
的 boundary
值带有 "
号。而 Postman 提交的表单请求,它的 boudary
值是没有双引号的。
那为什么会造成这样的差异呢?参考 这篇 博客的讲解,是由于各个系统/语言针对 RFC 2046 的实现不一致导致的。针对于 MultipartFormDataContent
的行为,如果 Boundary 后面的值带有双引号是符合标准的。
RFC 2612 原文:
- 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"}
};
使用 HttpClient 进行表单提交时,遇到的问题的更多相关文章
- 如何实现织梦dedecms表单提交时发送邮箱功能【已解决】
我们通过织梦系统制作网站时,很多客户需要有在线留言功能,这时就会用到自定义表单.但是很多用户觉得经常登陆后台查看留言信息太麻烦了,于是想能否在提交留言是直接把内容发送到指定邮箱.网站经过测试终于实现了 ...
- 表单提交时编码类型enctype详解
很早以前,当还没有前端这个概念的时候,我在写表单提交完全不去理会表单数据的编码,在action属性里写好目标URL,剩下的啊交给浏览器吧~但是现在,更多时候我们都采用Ajax方式提交数据,这种原始的方 ...
- form表单提交时选择性传值到后台
正常情况下form表单提交会把表单内的内容提交到后台,但是如果有些内容只是作为展示或者是标记而不想传到后台,我们采用如下方法: jsp页面如下,我们不想提交id为userIdMark和pwdMark的 ...
- jQuery判断 form表单提交时一些文本框的判断
一: form表单提交时如果表单里有input标签为空那么不提交form表单. <head> <script type="text/javascript"> ...
- php form表单提交时,action url中参数无效的解决方法
表单提交时get方式的一个错误 <form class="form-inline pull-right" method="get" action=&quo ...
- webform非表单提交时防xss攻击
1.webform默认配置下,主动防御了针对表单提交的xss攻击,但这次发生时因为url导致的,所以webform的默认防御机制不起作用 webform下输出非表单提交获得的数据的时候,要加htm ...
- 防止表单提交时刷新页面-阻止form表单的默认提交行为
最近在写 ajax 提交的时候遇到一个问题,在执行 ajax 提交之后,浏览器页面自动刷新了,主要是没有 由于form 表单的默认提交行为.一下是几种阻止 form 表单默认提交行为的方式. 1.使用 ...
- JS之表单提交时编码类型enctype详解
简介 form的enctype属性为编码方式,常用有两种:application/x-www-form-urlencoded和multipart/form-data,默认为application/x- ...
- SHOWMODALDIALOG表单提交时禁止打开新窗口
前提条件:showmodaldialog中有表单form.当action="#"的时候,提交表单,不会打开新窗口,但这种#自提有时不能用,#是本页面完整的带参数的url,如果表单中 ...
随机推荐
- 从零学React Native之10Text
在React Native开发中,所有需要显示的字符串文本都需要放置在Text或者Text的子组件中.虽然在之前的文章中多次使用了Text组件,但是Text组件还是值得专门学习的, 并没有想象中的那么 ...
- Redis源码解析:10scan类命令的实现
像keys或者smembers命令,需要遍历数据集合中的所有元素.在一个大的数据库中使用,可能会阻塞服务器较长的一段时间,造成性能问题,因此不适用与生产环境. 在Redis2.8.0中引入了scan类 ...
- huyingsakai的Python学习day1:计算机硬件
1.python是什么?Python是一门编程语言 2.什么是编程语言?(*****)程序员和计算机沟通交流的介质 3.什么是编程?(*****)编程就是程序员想把内心表达的方法用某种计算机语言思维表 ...
- Spring AOP 的@Aspect
Spring AOP 的@Aspect 转自:http://blog.csdn.net/tanghw/article/details/3862987 从Spring 2.0开始,可以使用基于sch ...
- 「BZOJ1005」[HNOI2008] 明明的烦恼
「BZOJ1005」[HNOI2008] 明明的烦恼 先放几个prufer序列的结论: Prufer序列是一种对有标号无根树的编码,长度为节点数-2. 具体存在无根树转化为prufer序列和prufe ...
- 学习C#泛型
C#泛型详解 C#菜鸟教程 C#中泛型的使用
- 源映射错误:request failed with status 404
源映射错误:request failed with status 404:源映射错误:request failed with status 404
- JIRA管理员、用户密码重置
-- Jira数据库中,用户信息都存放在表 cwd_user中 -- 切换到jiar数据库 use jiradb; -- 更改密码为sphere update cwd_user set credent ...
- 云原生生态周报 Vol. 6 | KubeCon EU 特刊
5 月 26日,2019 年第一个 KubeCon + CloudNativeCon 在巴塞罗那成功闭幕.本届 KubeCon 共吸引了超过 7700 名与会者,相较去年哥本哈根大会的 4300 余名 ...
- oracle避免在索引列上使用IS NULL和IS NOT NULL
避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引 .对于单列索引,如果列包含空值,索引中将不存在此记录. 对于复合索引,如果每个列都为空,索引中同样不存在此记录. 如果至少有一个列不为空 ...