C#记一次http协议multipart/form-data的boundary问题
作者:地狱高速公路 发布时间:2021-07-01 17:45:49
1.问题描述
使用post方法调用上级联网厂家接口,返回http状态码415,返回信息Content type ‘application/x-www-form-urlencoded’ not supported
测试上级联网厂家接口使用的是Postman工具,工具下载地址:https://www.getpostman.com/downloads/
使用application/x-www-form-urlencoded调用接口,返回http状态码415,如图:
既然服务器无法处理请求附带的媒体格式,那么改用multipart/form-data试试?
测试后发现可以调用成功,如图:
我们都知道ContentType为application/x-www-form-urlencoded的请求头、体如何构造,如:
HttpWebRequest request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
request.Method = "POST";
request.Host = Properties.Settings.Default.IP;
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
request.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko";
request.Accept = "*/*";
request.CookieContainer = cc;
request.KeepAlive = true;
string postData = string.Format("action=cx&hphm={0}&hpzl=&jclb=&detlsh=&clpp=&clxh=&rlzl=&pfbz=&jcff=&evl=&staName={1}&detLineId=&syxz=&rqyi={2}&rqer={3}&RQXZ=JCRQ&CXJL=Jiance&cllb=&clgs=&zcrq=&zzl=&clsbdh=&syr=&ccdjrq=&page={4}&rows=10", hphm, staName, rqyi, rqer, page);
byte[] postdatabyte = Encoding.GetEncoding("utf-8").GetBytes(postData);
request.ContentLength = postdatabyte.Length;
using (Stream stream = request.GetRequestStream())
{
stream.Write(postdatabyte, 0, postdatabyte.Length);
}
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
{
string temp = reader.ReadToEnd();
}
但是!multipart/form-data的请求头与请求体该如何构造呢?像下面这样?
string url = "http://112.17.158.12:8180/intf/services/query";
HttpWebRequest request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
request.Method = "POST";
request.Host = "112.17.158.12:8180";
request.ContentType = "multipart/form-data; ";
request.UserAgent = "PostmanRuntime/7.17.1";
request.Accept = "*/*";
request.KeepAlive = true;
string postData = @"jkuser=33088102&jkpasswd=33088102&jsondata={""jkid"":""R10"",""requestTime"":""20190919110603"",""body"":[{""inspstationcode"":""33088102""}]}";
byte[] postdatabyte = Encoding.GetEncoding("utf-8").GetBytes(postData);
request.ContentLength = postdatabyte.Length;
using (Stream stream = request.GetRequestStream())
{
stream.Write(postdatabyte, 0, postdatabyte.Length);
}
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
{
string temp = reader.ReadToEnd();
}
显然不对,捕获到了"远程服务器返回错误:(500)内部服务器错误。"异常,那么我们该怎么办呢?
2.解决思路
既然Postman工具使用ContentType为multipart/form-data类型post数据可以成功,那么我们写的C#程序应该也可以呀!那怎么办呢?。。。。没错!!就是抓包!
首先想到的是,用fiddler抓Postman的数据包,然后C#程序构造同样的数据包即可。
观察数据包Headers选项卡,如图:
发现Content-Type: multipart/form-data;后面跟了一个boundary=----------------------------183584948778966847113836
并且TextView选项卡如下:
WebForms选项卡如下:
所以,可以按照Headers和TextView选项卡内容构造post请求,就可以解决我们的问题了!
3.解决步骤
将ContentType加上boundary=boundary-------------------------xxxxxxxxxxxxxx
并且构造参数,如下:
string url = "http://112.17.158.12:8180/intf/services/query";
string boundary = "--------------------------" + DateTime.Now.Ticks.ToString("x");
string boundary2 = "--" + boundary;
HttpWebRequest request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
request.Method = "POST";
request.Host = "112.17.158.12:8180";
request.ContentType = "multipart/form-data; boundary=" + boundary;
request.UserAgent = "PostmanRuntime/7.17.1";
request.Accept = "*/*";
request.KeepAlive = true;
StringBuilder sb = new StringBuilder();
sb.Append(boundary2 + "\r\n");
sb.Append(@"Content-Disposition: form-data; name=""jkuser""" + "\r\n\r\n");
sb.Append("33088102" + "\r\n");
sb.Append(boundary2 + "\r\n");
sb.Append(@"Content-Disposition: form-data; name=""jkpasswd""" + "\r\n\r\n");
sb.Append("33088102" + "\r\n");
sb.Append(boundary2 + "\r\n");
sb.Append(@"Content-Disposition: form-data; name=""jsondata""" + "\r\n\r\n");
sb.Append(@"{""jkid"":""R10"",""requestTime"":""20190919110603"",""body"":[{""inspstationcode"":""33088102""}]}" + "\r\n");
sb.Append(boundary2 + "--" + "\r\n");
string postData = sb.ToString();
byte[] postdatabyte = Encoding.GetEncoding("utf-8").GetBytes(postData);
request.ContentLength = postdatabyte.Length;
using (Stream stream = request.GetRequestStream())
{
stream.Write(postdatabyte, 0, postdatabyte.Length);
}
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
{
string temp = reader.ReadToEnd();
}
值得注意的是,“boundary-------------------------xxxxxxxxxxxxxx”
这么长一串东西,只是作为分隔符出现的,不必太在意它是什么东西,我将它理解为分割文本参数的这么一个东西,并且通过仔细观察发现可以发现header中contenttype的横线数量比参数中横线数量少两个且必须少两个?
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
来源:https://cylycgs.blog.csdn.net/article/details/101019468


猜你喜欢
- 本文实例为大家分享了Android表格布局TableLayout的具体代码,供大家参考,具体内容如下1.TableLayout TableL
- 1.理解装箱简单地说,装箱就是将一个值类型的数据存储在一个引用类型的变量中。假设你一个方法中创建了一个 int 类型的本地变量,你要将这个值
- 原理拓展函数是kotlin里一个比较常用的特性,例如我们可以给Context拓展一个toast方法:// MainActivity.ktfu
- 本文实例为大家分享了Android实现简单banner轮播图的具体代码,供大家参考,具体内容如下说明:想玩一个简单的轮播图效果
- MapperScan添加动态配置(占位符)在对Mybatis自动扫描配置中,使用注解配置时,@MapperScan中的配置,通常配置如下:@
- Android:Field can be converted to a local varible.的解决办法前言:使用 Android S
- 本文研究的主要是Hibernate hql查询的相关内容,具体如下。HQL介绍Hibernate语言查询(Hibernate Query L
- 本文实例讲述了在WPF中动态加载XAML中的控件的方法。分享给大家供大家参考,具体如下:using System;using System.
- 以在搜索框搜索时,自动补全为例:其中还涉及到一个词,Tokenizer:分词器,分解器。上效果图:MainActivity.java:pac
- spring boot框架中已经集成了redis,在1.x.x的版本时默认使用的jedis客户端,现在是2.x.x版本默认使用的lettuc
- 前言在unity的ugui中Text控件,有时我们会有各种各样的需求,比如类似html中css的text-overflow属性,希望一段文字
- 目录为什么选择MQTTMQTT, 启动!使用方式Client模式创建工厂类创建工具类Spring Integration总结为什么选择MQT
- 本文实例介绍了Android如何画出触摸轨迹的方法,分享给大家供大家参考,具体内容如下效果图:实现代码:package com.androi
- 使用ProcessBuilder踩到的坑最近使用ProcessBuilder执行命令,命令内容正确,但始终报错命令实行失败,是因为不熟悉Pr
- 首先是获取特定进程对象,可以使用Process.GetProcesses()方法来获取系统中运行的所有进程,或者使用Process.GetC
- 前言:线程池是一个非常重要的知识点,也是池化技术的一个典型应用,相信很多人都有使用线程池的经历,但是对于线程池的实现原理大家都了解吗?本篇文
- 一、JDK中常见的异常情况1、常见异常总结图2、java中异常分类Throwable类有两个直接子类:(1)Exception:出现的问题是
- 本文实例讲述了Java实现删除排序数组中重复元素的方法。分享给大家供大家参考,具体如下:题目描述:给定一个排序数组,在原数组中删除重复出现的
- 因项目集成了Redis缓存部分数据,需要在程序启动时将数据加载到Redis中,即初始化数据到Redis。在SpringBoot项目下,即在容
- Android RecycleView添加head配置封装的实例这个是把RecycleView的适配器给封装了,直接调用就可以了,还添加了可