由于业务需求,最近需要模拟完成登陆某个网站,并上传所需要的文件。在开发途中,遇到了很多问题,现在,就我遇到的一些问题及解决办法说明如下,希望对遇到同样问题的人有所帮助。因为技术有限,可能有些内容并不完全正确或者理解有偏差,希望大家不要见怪,有不同的想法可以留言,我们共同学习,这也是我开始写博客的初衷之一。

  模拟请求,首先我觉得我们需要明确的是,模拟那些请求,我们模拟请求要完成那些操作,就拿我上面的功能来说,我需要模拟登录某个网站,然后打开固定的页面,输入关键字,查找相关信息,然后上传所需要的文件。那么这一系列就是需要我模拟完成的请求。为什么这么说呢,因为做过模拟登录的人可能知道,打开一个网站,他会有很多的请求,你不可能逐一的完成所有的请求,我们只需要模拟完成我们需要的几个请求就可以了。搞清楚我们需要模拟那些请求,接下来我们就可以开发了。

  因为工作的特殊性,无法将我开发的项目拿出来讲解,所以我就将具体问题跟大家分享一下。

  一、请求头的的设置:

    对于一个特定的网站,一般而言,请求头大致是相同的,因此我们可以设置一个统一的请求头,这么做的好处详细大家能够想的到。定义好这个请求头后,在以后的请求中可以直接把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=" + 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设置、文件上传等问题汇总的更多相关文章

  1. IIS 7 中设置文件上传大小的方法

    在IIS 6.0中设置文件上传大小的方法,就是配置如下节点: <system.web> <httpRuntime maxRequestLength="1918200&quo ...

  2. struts2设置文件上传大小

    利用struts2想要设置或者限制上传文件的大小,可以在struts.xml配置文件里面进行如下配置: <constant name="struts.multipart.maxSize ...

  3. IIS 6和IIS 7 中设置文件上传大小限制设置方法,两者是不一样的

    在IIS 6.0中设置文件上传大小的方法,只要设置httpRuntime就可以了 <system.web> <httpRuntime executionTimeout="3 ...

  4. SpringBoot2.x设置文件上传文件的大小

    The field file exceeds its maximum permitted size of 1048576 bytes spring: # 设置文件上传文件大小 servlet: mul ...

  5. php修改配置文件php.ini设置文件上传大小讲解

    打开php.ini,首先找到;;;;;;;;;;;;;;;;; File Uploads ;;;;;;;;;;;;;;;;;区域,有影响文件上传的以下几个参数: file_uploads   =   ...

  6. Spring boot2.0 设置文件上传大小限制

    今天把Spring boot版本升级到了2.0后,发现原来的文件上传大小限制设置不起作用了,原来的application.properties设置如下: spring.http.multipart.m ...

  7. node.js获取请求参数的方法和文件上传

    var http=require('http') var url=require('url') var qs=require('querystring') http.createServer(onRe ...

  8. Linux(Centos)配置vsftp使用账号密码(虚拟用户)登录ftp进行文件上传和修改

    安装vsftp yum install vsftpd -y 安装完成之后进入vsftp的配置文件夹 cd /etc/vsftpd/ 文件夹内容如下 [root@VM-0-12-centos vsftp ...

  9. nginx跨域设置&文件上传大小限制

    在部署项目的时候碰到这么一个问题:XMLHttpRequest cannot load,下面阐述一下这个问题 问题背景: 用nginx+tomcat部署项目.tomcat用的8080端口,nginx用 ...

随机推荐

  1. 第六章 图(b1)邻接矩阵

  2. Segments(叉积)

    Segments http://poj.org/problem?id=3304 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: ...

  3. PS切图导出代码后出现的图片布局散乱的解决方法——table布局

    前言: 一般来说,大部分美工PS切图后导出的都是使用PS默认的table布局的页面,出现最多的异常是上传代码,替换图片后,发现图片布局散乱,完全不是想要的效果.轻微的是浏览器不兼容,只有部分浏览器可以 ...

  4. MYSQL错误:You can't specify target table for update in FROM clause

    这句话意思是:不能先select再更新(修改)同一个表. 可以再外嵌套多一层,这个问题只有mysql有,mssql和oracle都没有. # 出错delete from Person where Id ...

  5. 在控制台远程连接mysql数据库时,出现ERROR 2049 (HY000)错误

    问题的原因是,你本地的数据库版本过高,而远程的数据库版本低. 解决方法:在连接时加上  --skip-secure-auth 参数就可以了. mysql -h主机 -u用户名 -p密码 --skip- ...

  6. OpenGLES.Functions.Missing.in.OpenGLES1.x

    转载自: http://maniacdev.com/2009/05/big-list-of-opengl-functions-missing-in-iphone-opengl-es The funct ...

  7. 将Win7笔记本设置成WiFi热点(无线路由器)

    查看是否能启动WiFi网卡: S1:运行cmd命令,打开命令提示符窗口(以管理员身份运行). S2:在命令行输入:netsh wlan show drivers. 若“支持的承载网络”后为“是”,则可 ...

  8. Debian 使用 cron 执行定时任务

    在linux下有两种方法来让一个命令或者脚本执行: crontab : 执行一个任务一次或者多次. at : 只执行一次. crontab是通过读取一个crontab文件来工作,这是一个普通的文本文件 ...

  9. Devexpress VCL Build v2013 vol 14.1.3 发布

    我修,我修,修修修. New Major Features in 14.1 What's New in VCL Products 14.1 Breaking Changes To learn abou ...

  10. 使用delphi 开发多层应用(二十三)KbmMW 的WIB

    解释WIB 是什么之前,先回顾以下我们前面的各种服务工作方式.前面的各种服务的工作方式都是请求/应答方式. 客户端发送请求,服务器端根据客户端的请求,返回相应的结果.这种方式是一种顺序式访问,是一种紧 ...