C#模拟请求,模拟登录,Cookie设置、文件上传等问题汇总
由于业务需求,最近需要模拟完成登陆某个网站,并上传所需要的文件。在开发途中,遇到了很多问题,现在,就我遇到的一些问题及解决办法说明如下,希望对遇到同样问题的人有所帮助。因为技术有限,可能有些内容并不完全正确或者理解有偏差,希望大家不要见怪,有不同的想法可以留言,我们共同学习,这也是我开始写博客的初衷之一。
模拟请求,首先我觉得我们需要明确的是,模拟那些请求,我们模拟请求要完成那些操作,就拿我上面的功能来说,我需要模拟登录某个网站,然后打开固定的页面,输入关键字,查找相关信息,然后上传所需要的文件。那么这一系列就是需要我模拟完成的请求。为什么这么说呢,因为做过模拟登录的人可能知道,打开一个网站,他会有很多的请求,你不可能逐一的完成所有的请求,我们只需要模拟完成我们需要的几个请求就可以了。搞清楚我们需要模拟那些请求,接下来我们就可以开发了。
因为工作的特殊性,无法将我开发的项目拿出来讲解,所以我就将具体问题跟大家分享一下。
一、请求头的的设置:
对于一个特定的网站,一般而言,请求头大致是相同的,因此我们可以设置一个统一的请求头,这么做的好处详细大家能够想的到。定义好这个请求头后,在以后的请求中可以直接把collection当做参数传递下去就可以了。
NameValueCollection collection = new NameValueCollection();
collection.Add("Accept","text/html, application/xhtml+xml, */*");
collection.Add("Accept-Encoding","gzip, deflate");
collection.Add("Accept-Language","zh-CN");
collection.Add("UserAgent","Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko");
二、HttpWebRequest和HttpWebResponse的创建,以及模拟请求:在此我把我项目中完成用户登录的模拟请求代码贴出来供大家参考
HttpWebRequest requestLoginToPage = (HttpWebRequest)WebRequest.Create(Url);//创建HttpWebRequest对象
requestLoginToPage.Headers.Add(collection);//添加定义好的请求头
requestLoginToPage.Referer = Url;//重定向地址
requestLoginToPage.ContentType = "application/x-www-form-urlencoded";
requestLoginToPage.Host = IP;
requestLoginToPage.Headers.Add("Pragma", "no-cache");
requestLoginToPage.Headers.Add("DNT","1");
requestLoginToPage.KeepAlive = true;//保持连接
requestLoginToPage.CookieContainer =cookieContainer;//设置Cookie的值
requestLoginToPage.Method = "POST";//请求方法,有POST和GET两种
requestLoginToPage.AllowAutoRedirect = false;//禁止页面重定向,在这里禁止重定向是因为要取当前请求响应头中的值,所以才禁止重定向
//login
//账户 密码
if (username == null) { username = ""; }
if (psw == null) { psw = ""; }
string data = "";
//请求参数,每个网站传递参数的形式不一样,具体情况要分析抓取结果,有的可能会进行特殊的编码处理,有的会在后边加时间戳,我使用Fiddle4抓包的,使用方法后期博文中会贴出
data = "username=" + username + "&password=" + psw + "&scope=<=" + lt + "&_eventId=submit";
if (data != null)//if之内的是对于需要传递参数特定的形式,我也不太清楚为什么要这么写,有知道的可以告诉我
{
byte[] bytes = Encoding.ASCII.GetBytes(data);
requestLoginToPage.ContentLength = bytes.Length;
Stream streamLoginToPage = requestLoginToPage.GetRequestStream();
streamLoginToPage.Write(bytes, 0, bytes.Length);
streamLoginToPage.Flush();
streamLoginToPage.Close();
}
//响应请求
HttpWebResponse responseLoginToPage = (HttpWebResponse)requestLoginToPage.GetResponse();
//这是得到响应请求中的Location的值,前边禁止重定向就是为了得到它。
string Locathion = responseLoginToPage.Headers["Location"].ToString();
在此,就完成了用户登录,注释都是我重新写的,简单的对代码做以说明。那么在实际的请求中,我们可能还会遇到其他的情况,下边列举一下:
三、读取响应的整个HTML页面
HttpWebResponse ResponseResult = (HttpWebResponse)RequestResult.GetResponse();//响应请求
string shtml = new StreamReader(ResponseResult.GetResponseStream(), Encoding.UTF8).ReadToEnd();//读取返回的HTML页面。
在开发中,我们肯定会要得到返回的页面,解析页面,得到我们需要的参数。这样就能够得到页面,其次就是分析页面,得到参数,在这里,大家一定要会用正则表达式还有简单的string字符串的操作。
四、参数值的处理
我没做过Web开发,不是很了解Web请求参数传递是不是一定要进行转码,但是我这个项目它进行了转码,所以这样对于我们处理参数会造成一定的困难,在这里给大家做个简单的演示
string dataPath = "_PARAMS=%7B%22NAjlb%22%3A%222%22%2C%22CAh%22%3A%22"
+ cbh
+ "%22%2C%22runTimeType%22%3A%22update%22%2C%22CBhAj%22%3A%22"
+ CBhAj
+ "%22%2C%22formType%22%3A%221%22%2C%22CYwlx%22%3A%22"
+ nYwlx
+ "%22%2C%22jzid%22%3A%22"
+ jzid
+ "%22%2C%22SystemName%22%3A%22npfy%22%2C%22NFyid%22%3A%22"
+ nFyid
+ "%22%2C%22limitTime%22%3A%220%22%2C%22getDataScript%22%3A%22Artery.get(%5C%22JZDataExplorerView%5C%22).data%22%2C%22formid%22%3A%22"
+ fID
+ "%22%7D&_CMD=_CMD_LAD_ZZZ_WJ&formid="
+ ID
+ "&itemid=dataUploadView&itemType=DzjzFileDiskView";
上边是我处理的一个参数,大家看到了,它进行了转码。对于处理这类参数,我的建议是,直接复制我们抓取的参数,然后一一比对,那些参数是一定会变的,那些参数是固定的,然后从前边的请求中找到那些变的参数,把他们进行转码,加进去就可以了,下边把编码函数贴给大家。
private string UrlEncode(string str)
{
StringBuilder sb = new StringBuilder();
byte[] byStr = System.Text.Encoding.UTF8.GetBytes(str);
for (int i = ; i < byStr.Length; i++)
{
sb.Append(@"%" + Convert.ToString(byStr[i], ));
}
return sb.ToString();
}
五、多文件上传问题:
对于多文件上传问题,有单独的博客说,我在这里也介绍一下,直接贴出代码:
string boundary = DateTime.Now.Ticks.ToString("X");// 随机分隔线,用来分隔参数,必须要有
request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);//web开发的可能知道这个multipart/form-data,多文件上传
request.UserAgent = "Shockwave Flash"; string str = "\r\n--" + boundary + "\r\n";
byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes(str);//开始标志
byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");//结束标志。注意,开始标志和结束标志是不一样的,而且一定要有这两,千万别搞错
//这里也值得注意,很明显这是同一个参数,但是他们中间有一个\r\n\r\n,千万别拉了这个,这个不一定有啊,但是当你出现服务器内部返回错误的错误信息时,而且其他地方都没问题
//那么一定是你参数的问题,很可能就是因为少了\r\n\r\n这个东西,我就在这吃过大亏,调试了好久才发现。 byte[] endbytes = Encoding.UTF8.GetBytes("Content-Disposition: form-data; name=\"Upload\"\r\n\r\nSubmit Query"); int pos = path.LastIndexOf("\\");
string fileName = path.Substring(pos + 1); string sbHeader = "Content-Disposition: form-data; name=\"Filename\""
+ "\r\n" + "\r\n"
+ fileName + str.ToString()
+ "Content-Disposition: form-data; name=\"_CMD\""
+ "\r\n" + "\r\n"
+ "_CMD_ADD_CL_DATA" + str.ToString()
+ "Content-Disposition: form-data; name=\"itemType\""
+ "\r\n" + "\r\n"
+ "DataUpload" + str.ToString()
+ "Content-Disposition: form-data; name=\"itemid\""
+ "\r\n" + "\r\n"
+ "dataUploadCtl" + str.ToString()
+ "Content-Disposition: form-data; name=\"_PARAMS\""
+ "\r\n" + "\r\n"
+ "{\"formid\":\"3685c2d13fb6da11aa5598995eb6e7c2\","//上传文件的formid
+ "\"itemid\":\"dataUploadCtl\","
+ "\"itemType\":\"DataUpload\","
+ "\"runTimeType\":\"update\","
+"\"tiffSize\":\"0\","
+ "\"storePath\":\"" + storePath + "\","
+"\"mp4Size\":\"0\","
+"\"formType\":\"1\",\"jpgSize\":\"0\","
+ "\"getNotifyObjScript\":\"uploadBaseDataHandler\","
+"\"fromOrder\":\""+i+"\",\"pngSize\":\"0\",\"mpegSize\":\"0\","
+ "\"getParamsObjScript\":\"upload_getParamsObjScript()\","
+ "\"parentId\":\"" + parentId + "\",\"rmvbSize\":\"0\","
+ "\"jzid\":\"" + jzid + "\",\"limitTime\":\"0\",\"dpi\":\"200\",\"parentName\":\"" + parentName + "\",\"tifSize\":\"0\","
+ "\"fileType\":\"*.doc;*.docx;*.pdf;*.jpg;*.jpeg;*.tif;*.tiff;*.bmp;*.png;*.xls;*.xlsx\","
+"\"wmaSize\":\"0\",\"jpegSize\":\"0\",\"fileUploadCount\":\"200\","
+ "\"getDataScript\":\"Artery.getWin().get(\\\"JZDataExplorerView\\\").data\","
+ "\"fileCount\":\"200\",\"wmvSize\":\"0\",\"bmpSize\":\"0\",\"cmd\":\"_CMD_ADD_CL_DATA\","
+"\"aviSize\":\"0\",\"mp3Size\":\"0\",\"wavSize\":\"0\","
+ "\"mode\":\"1\",\"clName\":\"\",\"parentData\":{\"typeIcon\":\"\",\"bz\":\"\",\"state\":\"\","//mod:1表示修改文件名称
+ "\"children\":[],\"leaf\":\"false\",\"type\":\"MU_LU\",\"date\":\"\",\"build\":false,"
+ "\"opms\":\"\",\"mode\":\"dir\",\"id\":\"" + id + "\",\"ywlx\":0,\"time\":-1,\"order\":"+order+",\"page\":0,"
+ "\"userId\":\"\",\"name\":\"" + parentName + "\",\"path\":\"" + path_url + "\","
+ "\"fcid\":\"" + fcid + "\",\"ot\":\"\",\"icon\":\"/dzjz/artery/arteryImage/cmpt/dzjz/type/MU_LU/SMALL-NORMAL.png\","
+ "\"extState\":\"\",\"pageCount\":0,\"ysid\":\"\",\"extType\":\"\","
+ "\"pid\":\"" + pid + "\",\"params\":\"\",\"size\":0,\"md5\":\"\",\"thumb\":\"\",\"shortName\":\""+parentName+"\",\"index\":1,\"image\":\"/dzjz/artery/arteryImage/cmpt/dzjz/type/MU_LU/NORMAL-NORMAL.png\"},"
+ "\"fileId\":\"SWFUpload_dataUploadCtl0_0\"}"
+ str.ToString()
+ "Content-Disposition: form-data; name=\"formid\""
+ "\r\n" + "\r\n"
+ "d6bda041e7e2ed5ff5e416c8e27e2dd2" + str.ToString()
+ "Content-Disposition: form-data; name=\"dataUploadCtl\";filename=\"" + fileName + "\"\r\nContent-Type: application/octet-stream"
+ "\r\n" + "\r\n"; byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)fs.Length))]; Stream postStream = new MemoryStream();
postStream = request.GetRequestStream();
postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);//写入数据流文件
postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
int byteRead = 0;
while ((byteRead = fs.Read(buffer, 0, buffer.Length)) != 0)
postStream.Write(buffer, 0, byteRead);
postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
postStream.Write(endbytes, 0, endbytes.Length);
postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length); postStream.Close(); //发送请求并获取相应回应数据
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
Stream instream = response.GetResponseStream();
本想很系统的写出来,但是发现自己的技术远远不够,写的可能不够清楚,但是基本模拟请求基本的内容都涉及到了,还有就是cookie的读取和设置问题,这网上都能够找到,如果有其他的问题,欢迎留言,我们集体讨论。下边再强调几个重要的问题:
1.如果你的请求中出现了跳转到登录页面的情况,那一定是你传递的Cookie值错了,如果牵扯到跨域名传cookie的情况,就更加麻烦了。
2.出现服务器内部错误,如果浏览器不报这个错误,那一定是你传递的参数有错误。
3.请求头部不是那么重要,当出现请求失败或其他错误的时候,不必太纠结在请求头部中。
4.有一个小经验,在开发的时候遇到过这种情况,就是当打开Fiddler的时候,全程的模拟都没有问题,而且请求响应速度也相当快,但是关闭Fiddler以后,有些请求响应特别慢,以至于响应超时。对于这种问题,我是采取这种方式解决的,也不知道具体原因,反正就是有效。
ServicePointManager.DefaultConnectionLimit = 200;这句代码的意思是将ServicePoin的最大请求并发连接数设置为200,默认的连接数是2,这个值就太小了。所以你可以将他的值设的相对大一些但是最好不要超过1024.
C#模拟请求,模拟登录,Cookie设置、文件上传等问题汇总的更多相关文章
- IIS 7 中设置文件上传大小的方法
在IIS 6.0中设置文件上传大小的方法,就是配置如下节点: <system.web> <httpRuntime maxRequestLength="1918200&quo ...
- struts2设置文件上传大小
利用struts2想要设置或者限制上传文件的大小,可以在struts.xml配置文件里面进行如下配置: <constant name="struts.multipart.maxSize ...
- IIS 6和IIS 7 中设置文件上传大小限制设置方法,两者是不一样的
在IIS 6.0中设置文件上传大小的方法,只要设置httpRuntime就可以了 <system.web> <httpRuntime executionTimeout="3 ...
- SpringBoot2.x设置文件上传文件的大小
The field file exceeds its maximum permitted size of 1048576 bytes spring: # 设置文件上传文件大小 servlet: mul ...
- php修改配置文件php.ini设置文件上传大小讲解
打开php.ini,首先找到;;;;;;;;;;;;;;;;; File Uploads ;;;;;;;;;;;;;;;;;区域,有影响文件上传的以下几个参数: file_uploads = ...
- Spring boot2.0 设置文件上传大小限制
今天把Spring boot版本升级到了2.0后,发现原来的文件上传大小限制设置不起作用了,原来的application.properties设置如下: spring.http.multipart.m ...
- node.js获取请求参数的方法和文件上传
var http=require('http') var url=require('url') var qs=require('querystring') http.createServer(onRe ...
- Linux(Centos)配置vsftp使用账号密码(虚拟用户)登录ftp进行文件上传和修改
安装vsftp yum install vsftpd -y 安装完成之后进入vsftp的配置文件夹 cd /etc/vsftpd/ 文件夹内容如下 [root@VM-0-12-centos vsftp ...
- nginx跨域设置&文件上传大小限制
在部署项目的时候碰到这么一个问题:XMLHttpRequest cannot load,下面阐述一下这个问题 问题背景: 用nginx+tomcat部署项目.tomcat用的8080端口,nginx用 ...
随机推荐
- springboot分环境打包(maven动态选择环境)
分环境打包核心点:spring.profiles.active pom.xml中添加: <profiles> <profile> <id>dev</id> ...
- vs code 插件推荐
通用插件 HTML Snippets 超级实用且初级的 H5代码片段以及提示 HTML CSS Support 让 html 标签上写class 智能提示当前项目所支持的样式新版已经支持scss文件检 ...
- ubuntu 下当前网速查看
ubuntu下用ethstatus可以监控实时的网卡带宽占用.这个软件能显示当前网卡的 RX 和 TX 速率,单位是Byte 一.安装 ethstatus 软件 #sudo apt-get insta ...
- Android logcat输出中文乱码
使用adb的logcat 命令查看系统日志缓冲区的内容,会发现在CMD的界面面,直接输出的中文内容是乱码. 这个问题出现在使用logcat将日志直接打印在当前的DOS窗口的时候会出现:使用logcat ...
- 使用css实现特殊标志或图形
1. 前言 由于图片占的空间比较大,且图片越多,越不好管理,所以有些时候,我们可以使用一些简单的标签样式来实现简单的图形标志来替代图片. 2. 实例展示: 三角形示例 示例代码: <style ...
- Mina入门:mina版之HelloWorld[z]
Mina入门:mina版之HelloWorld [z] 一,前言: 在完成上篇文章<Mina入门:Java NIO框架Mina.Netty.Grizzly简介与对比>之后,我们现在可以正式 ...
- PL/Sql快速执行 insert语句的.sql文件
当全是 insert语句的.sql文件太大时(insert 语句条数太大),直接打开执行sql文件,pl/sql会卡死. 这是可以用pl/sql的命令窗口来执行.sql文件,操作步骤如下: 1.新建命 ...
- CComSafeArray
https://blog.csdn.net/tangaowen/article/details/6554640
- Mina 系列(二)之基础
Mina 系列(二)之基础 Mina 使用起来多么简洁方便呀,就是不具备 Java NIO 的基础,只要了解 Mina 常用的 API,就可以灵活使用并完成应用开发. 1. Mina 概述 首先,看 ...
- Kendo UI中TreeView 放入tabstrip中,大数据量时超过边框的解决方案。
参考http://www.kendoui.com/forums/ui/tabstrip/tabstip-with-treeview-treeview-breaking-out-of-tabstrip. ...