使用C#模拟浏览器提交表单
浏览器也是一个普通的应用程序,.net framework也提供一些类也能让我们直接发起HTTP请求。 今天我将再次用C#来模拟浏览器的提交请求,同时也可以加深对HTTP请求的理解。
示例代码分为二段,一段示范了使用application/x-www-form-urlencoded编码方式提交, 另一段则示范了使用multipart/form-data的编码方式。
为了让大家能再次利用这些代码,我已将关键部分写成独立方法,希望当您有这方面的需求时能马上可以用上。 代码如下:
1. application/x-www-form-urlencoded
/// <summary> /// 向指定的URL地址发起一个POST请求,同时可以上传一些数据项。 /// </summary> /// <param name="url">要请求的URL地址</param> /// <param name="keyvalues">要上传的数据项</param> /// <param name="encoding">发送,接收的字符编码方式</param> /// <returns>服务器的返回结果</returns> static string SendHttpRequestPost(string url, Dictionary<string, string> keyvalues, Encoding encoding) { if( string.IsNullOrEmpty(url) ) throw new ArgumentNullException("url"); string postData = null; // 将数据项转变成 name1=value1&name2=value2 的形式 if( keyvalues != null && keyvalues.Count > 0 ) { postData = string.Join("&", (from kvp in keyvalues let item = kvp.Key + "=" + HttpUtility.UrlEncode(kvp.Value) select item ).ToArray() ); } if( encoding == null ) encoding = Encoding.UTF8; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded; charset=" + encoding.WebName; if( postData != null ) { byte[] buffer = encoding.GetBytes(postData); Stream stream = request.GetRequestStream(); stream.Write(buffer, 0, buffer.Length); stream.Close(); } using( WebResponse response = request.GetResponse() ) { using( StreamReader reader = new StreamReader(response.GetResponseStream(), encoding) ) { return reader.ReadToEnd(); } } } // 调用上面方法的示例代码 string Test_SendHttpRequestPost() { string url = "http://localhost:1272/FormWebSite1/Handler1.ashx"; Dictionary<string, string> keyvalues = new Dictionary<string, string>(); keyvalues.Add("CustomerName", "我是李奇峰,$%@+& ?#^/"); keyvalues.Add("CustomerTel", "1381723505x"); return SendHttpRequestPost(url, keyvalues, null); } 2. multipart/form-data 。注意这部分代码有点复杂,因此我加了很多注释。 /// <summary> /// 向指定的URL地址发起一个POST请求,同时可以上传一些数据项以及上传文件。 /// </summary> /// <param name="url">要请求的URL地址</param> /// <param name="keyvalues">要上传的数据项</param> /// <param name="fileList">要上传的文件列表</param> /// <param name="encoding">发送数据项,接收的字符编码方式</param> /// <returns>服务器的返回结果</returns> static string SendHttpRequestPost(string url, Dictionary<string, string> keyvalues, Dictionary<string, string> fileList, Encoding encoding) { if( fileList == null ) return SendHttpRequestPost(url, keyvalues, encoding); if( string.IsNullOrEmpty(url) ) throw new ArgumentNullException("url"); if( encoding == null ) encoding = Encoding.UTF8; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; // 要上传文件,一定要是POST方法 // 数据块的分隔标记,用于设置请求头,注意:这个地方最好不要使用汉字。 string boundary = "---------------------------" + Guid.NewGuid().ToString("N"); // 数据块的分隔标记,用于写入请求体。 // 注意:前面多了一段: "--" ,而且它们将独占一行。 byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); // 设置请求头。指示是一个上传表单,以及各数据块的分隔标记。 request.ContentType = "multipart/form-data; boundary=" + boundary; // 先得到请求流,准备写入数据。 Stream stream = request.GetRequestStream(); if( keyvalues != null && keyvalues.Count > 0 ) { // 写入非文件的keyvalues部分 foreach( KeyValuePair<string, string> kvp in keyvalues ) { // 写入数据块的分隔标记 stream.Write(boundaryBytes, 0, boundaryBytes.Length); // 写入数据项描述,这里的Value部分可以不用URL编码 string str = string.Format( "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}", kvp.Key, kvp.Value); byte[] data = encoding.GetBytes(str); stream.Write(data, 0, data.Length); } } // 写入要上传的文件 foreach( KeyValuePair<string, string> kvp in fileList ) { // 写入数据块的分隔标记 stream.Write(boundaryBytes, 0, boundaryBytes.Length); // 写入文件描述,这里设置一个通用的类型描述:application/octet-stream,具体的描述在注册表里有。 string description = string.Format( "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" + "Content-Type: application/octet-stream\r\n\r\n", kvp.Key, Path.GetFileName(kvp.Value)); // 注意:这里如果不使用UTF-8,对于汉字会有乱码。 byte[] header = Encoding.UTF8.GetBytes(description); stream.Write(header, 0, header.Length); // 写入文件内容 byte[] body = File.ReadAllBytes(kvp.Value); stream.Write(body, 0, body.Length); } // 写入结束标记 boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n"); stream.Write(boundaryBytes, 0, boundaryBytes.Length); stream.Close(); // 开始发起请求,并获取服务器返回的结果。 using( WebResponse response = request.GetResponse() ) { using( StreamReader reader = new StreamReader(response.GetResponseStream(), encoding) ) { return reader.ReadToEnd(); } } } // 调用上面方法的示例代码 string Test_SendHttpRequestPost2() { string url = "http://localhost:1272/FormWebSite1/Handler2.ashx"; Dictionary<string, string> keyvalues = new Dictionary<string, string>(); keyvalues.Add("Key1", "本示例代码由 Fish Li 提供"); keyvalues.Add("Key2", "http://www.cnblogs.com/fish-li"); keyvalues.Add("Key3", "来几个特殊字符:~!@#$%^&*()-=_+{}[]:;'\"<>?/.,|\\"); Dictionary<string, string> fileList = new Dictionary<string, string>(); fileList.Add("file1", @"H:\AllTempFiles\ascx中文字.gif"); fileList.Add("file2", @"H:\AllTempFiles\asax中文字.gif"); return SendHttpRequestPost(url, keyvalues, fileList, Encoding.UTF8); }
说明:上面的示例方法中,我并没有对KEY编码,是因为:我想大家选用的KEY应该是不需要编码的(英文字母与数字的组合)。
而且,我也没加入对Cookie处理的那部分代码,如果您需要在发送请求时,保留Cookie,那么请参考我上一篇博客 【细说Cookie】中的示例代码。
如果我的文章对你有帮助,就点一下推荐吧.(*^__^*)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步