Web后台或Winform程序与其他系统对接时,经常用到HTTP/HTTPS的接口调用,且多为Post,我从网上搜到了相关代码,并在使用过程中补充了三个参数,PostFormHelper.cs如下
using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; namespace Common { public static class FormUpload { private static readonly Encoding encoding = Encoding.UTF8; /// <summary> /// 提交表单 /// </summary> /// <param name="postUrl"></param> /// <param name="userAgent"></param> /// <param name="postParameters"></param> /// <param name="waitResponse">是否等待回复</param> /// <param name="token">不需要tocken则为string.Empty</param> /// <param name="timeOut">超时时间(毫秒),0-使用默认100秒</param> /// <returns></returns> public static string MultipartFormDataPost(string postUrl, string userAgent, Dictionary<string, object> postParameters, bool waitResponse, string token = "", int timeOut = 0) { string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid()); string contentType = "multipart/form-data; boundary=" + formDataBoundary; byte[] formData = GetMultipartFormData(postParameters, formDataBoundary); return PostForm(postUrl, userAgent, contentType, formData, waitResponse, token, timeOut); } private static string PostForm(string postUrl, string userAgent, string contentType, byte[] formData, bool waitResponse, string token, int timeOut) { HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest; if (request == null) { throw new NullReferenceException("request is not a http request"); } // Set up the request properties. request.Method = "POST"; if (!string.IsNullOrEmpty(token)) request.Headers.Add("token", token); request.ContentType = contentType; request.UserAgent = userAgent; request.CookieContainer = new CookieContainer(); request.ContentLength = formData.Length; if (timeOut > 0) request.Timeout = timeOut; using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(formData, 0, formData.Length); requestStream.Close(); } if (waitResponse) { Stream instream = request.GetResponse().GetResponseStream(); StreamReader sr = new StreamReader(instream, Encoding.UTF8); string response = sr.ReadToEnd(); return response; } else return string.Empty; } private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary) { Stream formDataStream = new System.IO.MemoryStream(); bool needsCLRF = false; foreach (var param in postParameters) { // Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added. // Skip it on the first parameter, add it to subsequent parameters. if (needsCLRF) formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n")); needsCLRF = true; if (param.Value is FileParameter) { FileParameter fileToUpload = (FileParameter)param.Value; // Add just the first part of this param, since we will write the file data directly to the Stream string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n", boundary, param.Key, fileToUpload.FileName ?? param.Key, fileToUpload.ContentType ?? "application/octet-stream"); formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header)); // Write the file data directly to the Stream, rather than serializing it to a string. formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length); } else { string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", boundary, param.Key, param.Value); formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData)); } } // Add the end of the request. Start with a newline string footer = "\r\n--" + boundary + "--\r\n"; formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer)); // Dump the Stream into a byte[] formDataStream.Position = 0; byte[] formData = new byte[formDataStream.Length]; formDataStream.Read(formData, 0, formData.Length); formDataStream.Close(); return formData; } public class FileParameter { public byte[] File { get; set; } public string FileName { get; set; } public string ContentType { get; set; } public FileParameter(byte[] file) : this(file, null) { } public FileParameter(byte[] file, string filename) : this(file, filename, null) { } public FileParameter(byte[] file, string filename, string contenttype) { File = file; FileName = filename; ContentType = contenttype; } } } }View Code
调用示例如下
string apiAddr = "http://{0}:80/v1/{1}"; string userAgent = "Mozilla / 5.0(Windows NT 6.1; WOW64; Trident / 7.0; rv: 11.0) like Gecko"; int timeOut = 1500; Dictionary<string, object> postParams = new Dictionary<string, object>(); postParams.Add("id", 1); postParams.Add("name", "John"); postParams.Add("image", new FormUpload.FileParameter(File.ReadAllBytes(image), "1.jpg")); string json = FormUpload.MultipartFormDataPost(apiAddr, userAgent, postParams, true, string.Empty, timeOut);
如果出现“基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系”的异常,可添加如下代码
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);//验证服务器证书回调自动验证 public static bool CheckValidationResult(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors errors) { // 总是接受 return true; }