发表于2015-10-16
其实使用网页上传图片或者其它文件时,表单为我们简化了文件的上传的过程。但是有时我们想把前台上传过来的文件在保存到服务器的时候同时提交到另外一个服务器地址并保存起来。要实现这个功能要利用HttpWebRequest模拟网页的表单提交过程。今天我就来分享一下我在ASP.NET mvc5中通过HttpWebRequest上传文件到服务器的实现方案。
首先我们来看看传统的表单提交过程。
当我们都是通过表单来上传文件。前台html代码:
<form enctype="multipart/form-data" action="/Upload/UploadPic" method="post" id="UploadForm"> <div style="padding:15px; text-align:left;"> <input type="file" style="margin-bottom:10px;" name="UploadImage" id="UploadImage"> <input type="submit" class="btn btn-primary" value="上传"> </div> </form>
把form标签的加一个enctype="multipart/form-data"属性,后台可以通过Request.Files获取到前台上传过来的文件,并且可以用file.SaveAs(fileFullPath)把文件保存下来。
using System; using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.linq; using System.Net; using System.Text; using System.Threading.Tasks; namespace Lanhu.Core { public class NetHelper { /// <summary> /// 通过HttpWebRequest上传文件到服务器 /// </summary> /// <param name="url">上传地址</param> /// <param name="file">文件所有位置</param> /// <param name="paramName">表单参数名</param> /// <param name="contentType">文件的contentType</param> /// <param name="nvc">其他参数集合</param> /// <returns></returns> public static string UploadFileByHttpWebRequest(string url, string file, string paramName, string contentType, NameValueCollection nvc) { string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url); wr.ContentType = "multipart/form-data; boundary=" + boundary; wr.Method = "POST"; wr.KeepAlive = true; wr.Credentials = System.Net.CredentialCache.DefaultCredentials; Stream rs = wr.GetRequestStream(); string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}"; if (nvc != null) { foreach (string key in nvc.Keys) { rs.Write(boundarybytes, 0, boundarybytes.Length); string formitem = string.Format(formdataTemplate, key, nvc[key]); byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem); rs.Write(formitembytes, 0, formitembytes.Length); } } rs.Write(boundarybytes, 0, boundarybytes.Length); string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n"; string header = string.Format(headerTemplate, paramName, file, contentType); byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header); rs.Write(headerbytes, 0, headerbytes.Length); FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read); byte[] buffer = new byte[4096]; int bytesRead = 0; while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) { rs.Write(buffer, 0, bytesRead); } fileStream.Close(); byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n"); rs.Write(trailer, 0, trailer.Length); rs.Close(); WebResponse wresp = null; var result = ""; try { wresp = wr.GetResponse(); Stream stream2 = wresp.GetResponseStream(); StreamReader reader2 = new StreamReader(stream2); //成功返回的結果 result = reader2.ReadToEnd(); } catch (Exception ex) { if (wresp != null) { wresp.Close(); } } wr = null; return result; } } }
上面使用HttpWebRequest采用二进制流的形式模拟一个表单提交过程,这样后台也可以采用传统形式获取传过来的文件。
using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Dynamic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Web; using System.Web.Mvc; namespace Lanhu.Admin.Controllers { public class UploadController : Controller { private string FilePhysicalPath = string.Empty; private string FileRelativePath = string.Empty; #region Private Methods /// <summary> /// 检查是否为合法的上传图片 /// </summary> /// <param name="_fileExt"></param> /// <returns></returns> private string CheckImage(HttpPostedFileBase imgfile) { string allowExt = ".gif.jpg.png"; string fileName = imgfile.FileName; FileInfo file = new FileInfo(fileName); string imgExt = file.Extension; Image img = IsImage(imgfile); string errorMsg = fileName + ":"; if (img == null) { errorMsg = "文件格式错误,请上传gif、jpg、png格式的图片"; return errorMsg; } if (allowExt.IndexOf(imgExt.ToLower()) == -1) { errorMsg = "请上传gif、jpg、png格式的图片;"; } //if (imgfile.ContentLength > 512 * 1024) //{ // errorMsg += "图片最大限制为0.5Mb;"; //} //if (img.Width < 20 || img.Width > 480 || img.Height < 20 || img.Height > 854) //{ // errorMsg += "请上传正确尺寸的图片,图片最小为20x20,最大为480*854。"; //} if (errorMsg == fileName + ":") { return ""; } return errorMsg; } /// <summary> /// 验证是否为真正的图片 /// </summary> /// <param name="file"></param> /// <returns></returns> private Image IsImage(HttpPostedFileBase file) { try { Image img = Image.FromStream(file.InputStream); return img; } catch { return null; } } private string NewFileName(string fileNameExt) { return DateTime.Now.ToString("yyyyMMddHHmmss_ffff", DateTimeFormatInfo.InvariantInfo) + fileNameExt; //return Guid.NewGuid().ToString() + fileNameExt; } private UploadImgResult UploadImage(HttpPostedFileBase file) { UploadImgResult result = new UploadImgResult(); try { string fileNameExt = (new FileInfo(file.FileName)).Extension; //string saveName = GetImageName() + fileNameExt; //获得要保存的文件路径 String newFileName = NewFileName(fileNameExt); String ymd = DateTime.Now.ToString("yyyyMMdd", DateTimeFormatInfo.InvariantInfo); FilePhysicalPath += ymd + "/"; FileRelativePath += ymd + "/"; String fileFullPath = FilePhysicalPath + newFileName; if (!Directory.Exists(FilePhysicalPath)) Directory.CreateDirectory(FilePhysicalPath); file.SaveAs(fileFullPath); string relativeFileFullPath = FileRelativePath + newFileName; result.Result = 1; result.msg = relativeFileFullPath; } catch (Exception ex) { result.Result = 3; result.msg = ex.Message; } return result; } private void showError(string message) { Hashtable hash = new Hashtable(); hash["error"] = 1; hash["message"] = message; Response.AddHeader("Content-Type", "text/html; charset=UTF-8"); Response.Write(JsonConvert.SerializeObject(hash)); Response.End(); } #endregion [HttpPost] public string UploadPic() { Response.ContentType = "text/plain"; List<UploadImgResult> results = new List<UploadImgResult>(); FileRelativePath = System.Configuration.ConfigurationManager.AppSettings["UploadProductImgPath"]; FilePhysicalPath = System.Web.HttpContext.Current.Server.MapPath(FileRelativePath); if (!Directory.Exists(FilePhysicalPath)) { Directory.CreateDirectory(FilePhysicalPath); } string saveFileResult = string.Empty; HttpFileCollectionBase files = (HttpFileCollectionBase)Request.Files; for (int i = 0; i < files.Count; i++) { HttpPostedFileBase file = files[i]; UploadImgResult result = null; string checkResult = CheckImage(file); if (string.IsNullOrEmpty(checkResult)) { result = UploadImage(file); } else { result = new UploadImgResult(); result.Result = 2; result.msg = checkResult; } results.Add(result); } string json = JsonConvert.SerializeObject(results); return json; } private void HandleWaterMark(string fileFullPath) { bool isWaterMask = Request.Form["watermask"] == "1"; if (isWaterMask) { string waterurl = Request.MapPath("/Content/water.png"); //CommonHelper.MakeWatermark(fileFullPath, waterurl, fileFullPath, 4, 95); } } public string FileManagerJson() { String aspxUrl = Request.Path.Substring(0, Request.Path.LastIndexOf("/") + 1); ////根目录路径,相对路径 //String rootPath = "../attached/"; ////根目录URL,可以指定绝对路径,比如 http://www.yoursite.com/attached/ //String rootUrl = aspxUrl + "../attached/"; //根目录路径,相对路径 String rootPath = System.Configuration.ConfigurationManager.AppSettings["UploadDir"]; //根目录URL,可以指定绝对路径,比如 http://www.yoursite.com/attached/ String rootUrl = System.Configuration.ConfigurationManager.AppSettings["UploadDir"]; //图片扩展名 String fileTypes = "gif,jpg,jpeg,png,bmp"; String currentPath = ""; String currentUrl = ""; String currentDirPath = ""; String moveupDirPath = ""; String dirPath = Server.MapPath(rootPath); String dirName = Request.QueryString["dir"]; if (!String.IsNullOrEmpty(dirName)) { if (Array.IndexOf("image,flash,media,file".Split(','), dirName) == -1) { return "Invalid Directory name."; } dirPath += dirName + "/"; rootUrl += dirName + "/"; if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } } //根据path参数,设置各路径和URL String path = Request.QueryString["path"]; path = String.IsNullOrEmpty(path) ? "" : path; if (path == "") { currentPath = dirPath; currentUrl = rootUrl; currentDirPath = ""; moveupDirPath = ""; } else { currentPath = dirPath + path; currentUrl = rootUrl + path; currentDirPath = path; moveupDirPath = Regex.Replace(currentDirPath, @"(.*?)[^\/]+\/$", "$1"); } //排序形式,name or size or type String order = Request.QueryString["order"]; order = String.IsNullOrEmpty(order) ? "" : order.ToLower(); //不允许使用..移动到上一级目录 if (Regex.IsMatch(path, @"\.\.")) { Response.Write("Access is not allowed."); Response.End(); } //最后一个字符不是/ if (path != "" && !path.EndsWith("/")) { Response.Write("Parameter is not valid."); Response.End(); } //目录不存在或不是目录 if (!Directory.Exists(currentPath)) { Response.Write("Directory does not exist."); Response.End(); } //遍历目录取得文件信息 string[] dirList = Directory.GetDirectories(currentPath); string[] fileList = Directory.GetFiles(currentPath); switch (order) { case "size": Array.Sort(dirList, new NameSorter()); Array.Sort(fileList, new SizeSorter()); break; case "type": Array.Sort(dirList, new NameSorter()); Array.Sort(fileList, new TypeSorter()); break; case "name": default: Array.Sort(dirList, new NameSorter()); Array.Sort(fileList, new NameSorter()); break; } Hashtable result = new Hashtable(); result["moveup_dir_path"] = moveupDirPath; result["current_dir_path"] = currentDirPath; result["current_url"] = currentUrl; result["total_count"] = dirList.Length + fileList.Length; List<Hashtable> dirFileList = new List<Hashtable>(); result["file_list"] = dirFileList; for (int i = 0; i < dirList.Length; i++) { DirectoryInfo dir = new DirectoryInfo(dirList[i]); Hashtable hash = new Hashtable(); hash["is_dir"] = true; hash["has_file"] = (dir.GetFileSystemInfos().Length > 0); hash["filesize"] = 0; hash["is_photo"] = false; hash["filetype"] = ""; hash["filename"] = dir.Name; hash["datetime"] = dir.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss"); dirFileList.Add(hash); } for (int i = 0; i < fileList.Length; i++) { FileInfo file = new FileInfo(fileList[i]); Hashtable hash = new Hashtable(); hash["is_dir"] = false; hash["has_file"] = false; hash["filesize"] = file.Length; hash["is_photo"] = (Array.IndexOf(fileTypes.Split(','), file.Extension.Substring(1).ToLower()) >= 0); hash["filetype"] = file.Extension.Substring(1); hash["filename"] = file.Name; hash["datetime"] = file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss"); dirFileList.Add(hash); } Response.AddHeader("Content-Type", "application/json; charset=UTF-8"); //Response.Write(JsonConvert.SerializeObject(result)); //Response.End(); return JsonConvert.SerializeObject(result); } } #region Model public class UploadImgResult { public int Result { set; get; } //1成功,2失败,3异常 public string msg { set; get; } } public class NameSorter : IComparer { public int Compare(object x, object y) { if (x == null && y == null) { return 0; } if (x == null) { return -1; } if (y == null) { return 1; } FileInfo xInfo = new FileInfo(x.ToString()); FileInfo yInfo = new FileInfo(y.ToString()); return xInfo.FullName.CompareTo(yInfo.FullName); } } public class SizeSorter : IComparer { public int Compare(object x, object y) { if (x == null && y == null) { return 0; } if (x == null) { return -1; } if (y == null) { return 1; } FileInfo xInfo = new FileInfo(x.ToString()); FileInfo yInfo = new FileInfo(y.ToString()); return xInfo.Length.CompareTo(yInfo.Length); } } public class TypeSorter : IComparer { public int Compare(object x, object y) { if (x == null && y == null) { return 0; } if (x == null) { return -1; } if (y == null) { return 1; } FileInfo xInfo = new FileInfo(x.ToString()); FileInfo yInfo = new FileInfo(y.ToString()); return xInfo.Extension.CompareTo(yInfo.Extension); } } #endregion }
这个处理上传图片的Controller中UploadPic就是对外公开的Action。要使用这个ASP.NET MVC5的Action上传图片你可以采用网页的表单也可以用上面我讲的用HttpWebRequest。
最后,我们来看看怎么使用我们头面封装的NetHelper把前台上传过来的文件在保存到服务器的时候同时提交到另外一个服务器地址并保存起来。
[HttpPost] public string UploadPic() { string json = ""; Response.ContentType = "text/plain"; List<UploadImgResult> results = new List<UploadImgResult>(); FileRelativePath = System.Configuration.ConfigurationManager.AppSettings["UploadProductImgPath"]; FilePhysicalPath = System.Web.HttpContext.Current.Server.MapPath(FileRelativePath); if (!Directory.Exists(FilePhysicalPath)) { Directory.CreateDirectory(FilePhysicalPath); } string saveFileResult = string.Empty; HttpFileCollectionBase files = (HttpFileCollectionBase)Request.Files; for (int i = 0; i < files.Count; i++) { HttpPostedFileBase file = files[i]; UploadImgResult result = null; string checkResult = CheckImage(file); if (string.IsNullOrEmpty(checkResult)) { //上传到本地并返回保存到所在服务器的相对地址 result = UploadImage(file); //将图片上传到远程的服务器 json=NetHelper.UploadFileByHttpWebRequest(Lanhusoft.Core.AppConfigHelper.ImageHost+"/Upload/UploadPic", Server.MapPath(result.msg), "uploadFileName", file.ContentType, null); //把远程服务器返回的保存图片相对地址替换成http开头的绝对地址 results = JsonConvert.DeserializeObject<List<UploadImgResult>>(json); //处理文件在远程服务器和本地服务器路径不一致的问题 FileInfo fi = new FileInfo(Server.MapPath(result.msg)); var dir=Path.GetDirectoryName(Server.MapPath(results[0].msg)); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); fi.MoveTo(Server.MapPath(results[0].msg)); return json; } else { result = new UploadImgResult(); result.Result = 2; result.msg = checkResult; results.Add(result); } } json = JsonConvert.SerializeObject(results); return json; }