文件上傳屬於常見業務,不少地方都用的到(好比圖片上傳);前端
確切的說,這裏的「本地」是指的項目所在的服務端,只是在項目服務端再次請求另一個服務端進行文件二次上傳。ios
好比:咱們上傳圖片的時候,請求項目的服務器須要上傳一份,同時還要上傳一份到cdn服務器。json
示例使用控件: el-upload 做爲演示axios
1 <style> 2 .uploader { 3 border: 1px dashed #d9d9d9; 4 border-radius: 6px; 5 cursor: pointer; 6 position: relative; 7 overflow: hidden; 8 } 9 10 .uploader:hover { 11 border-color: #409EFF; 12 } 13 14 .avatar-uploader-icon { 15 font-size: 28px; 16 color: #8c939d; 17 text-align: center; 18 } 19 20 .banners-size { 21 width: 280px; 22 height: 120px; 23 line-height: 120px; 24 } 25 26 .avatar-banners { 27 width: 280px; 28 height: 120px; 29 background-size: cover; 30 } 31 32 .el-upload__tip { 33 color: red; 34 } 35 </style>
1 <el-upload class="upload-demo" 2 ref="banners" 3 :limit="1" 4 action="https://jsonplaceholder.typicode.com/posts/" 5 accept="image/jpeg,image/png" 6 name="bannersImg" 7 :http-request="uploadFile" 8 :auto-upload="false"> 9 <el-button slot="trigger" size="small" type="primary" v-on:click="selectUpload('bannersImg')">選取文件</el-button> 10 <el-button style="margin-left: 10px;" size="small" type="success" v-on:click="submitUpload('bannersImg')">肯定上傳</el-button> 11 <div slot="tip" class="el-upload__tip">只能上傳jpg文件,且不超過200kb,尺寸:440x240</div> 12 </el-upload> 13 <div class="uploader banners-size"> 14 <img v-if="banners_imageUrl" :src="banners_imageUrl" class="avatar-banners"> 15 </div>
前端核心代碼:api
1 //選取文件 2 selectUpload: function (obj) { 3 this.clearFiles(obj); 4 }, 5 //肯定上傳 6 submitUpload: function (obj) { 7 this.$refs.banners.submit(); 8 }, 9 //清除文件狀態 10 clearFiles: function (filename) { 11 this.$refs.banners.clearFiles(); 12 }, 13 14 //文件上傳 15 uploadFile: function (params) { 16 //console.log(params); 17 var _filename = params.filename; 18 19 //判斷圖片格式 20 const isJPG = params.file.type === 'image/jpeg'; 21 if (!isJPG) { 22 this.$message.error('上傳圖片只能是 JPG 格式!'); 23 this.clearFiles(_filename); 24 return isJPG; 25 } 26 this.BannersUpload(params.file); 27 }, 28 //圖片上傳 29 BannersUpload: function (file) { 30 const isLtSize = file.size / 1024 / 1024 / 1024 < 20; //不能超過xx kb 31 if (!isLtSize) { 32 this.$message.error('上傳圖片大小不能超過 20kb!'); 33 this.clearFiles(file.filename); 34 return isLtSize; 35 } 36 37 //執行上傳操做 38 this.FileUpload(file) 39 .then(res => { //返回結果 40 var getResult = JSON.parse(res.data); 41 //成功 42 if (getResult.Code == 0) { 43 this.$message.success('上傳成功'); 44 this.banners_imageUrl = getResult.Data; 45 this.addForm.BannersImg = getResult.Data; 46 } 47 //錯誤 48 if (getResult.Code == 1) { 49 if (getResult.Message) { 50 this.$message.error(getResult.Message); 51 } 52 } 53 }).catch(function (res) { 54 this.$message.success('請求異常'); 55 }); 56 }, 57 //文件上傳 58 FileUpload: function (file) { 59 var fd = new FormData(); 60 fd.append("filedata", file); 61 //異步獲取 62 return axios.request({ 63 method: 'post', 64 baseURL: this.apiUrl, 65 url: '/WxLive/UploadImg', 66 params: { "filename": "filedata" }, //是即將與請求一塊兒發送的 URL 參數 67 data: fd, //瀏覽器專屬:FormData, File, Blob 必須是如下類型之一:string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams 68 headers: { "Content-Type": "multipart/form-data;charset=UTF-8" }, 69 }); 70 }
本地服務器上傳接口:瀏覽器
1 /// <summary> 2 /// 本地上傳圖片 3 /// </summary> 4 /// <returns></returns> 5 [HttpPost] 6 public JsonResult UploadImg(string filename) 7 { 8 var result = new Common.CommonResult(1, "網絡請求錯誤"); 9 try 10 { 11 string basePath = ConfigurationManager.AppSettings["basePath"] ?? "\\Images"; //服務器上傳文件夾 12 string imgpath = string.Empty; 13 14 HttpPostedFileBase file = Request.Files.Get(filename); //從browser傳過來的的文件 15 //HttpPostedFile file = System.Web.HttpContext.Current.Request.Files.Get(filename); //從browser傳過來的的文件 16 17 if (file != null && file.ContentLength > 0) 18 { 19 //文件後綴名 20 string fileExtension = Path.GetExtension(file.FileName).ToLower(); 21 22 //獲取文件名 23 string fileName = DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss_ffff"); 24 fileName += fileExtension; 25 26 Stream postStream = file.InputStream; 27 byte[] bytes = new byte[postStream.Length]; 28 postStream.Read(bytes, 0, file.ContentLength); 29 postStream.Seek(0, SeekOrigin.Begin); //設置當前流的位置爲流的開始 30 postStream.Close(); 31 32 //寫入本地 33 var repath = UploadHelper.UploadFile(bytes, basePath, fileName); 34 35 result.Code = 0; 36 result.Message = "OK"; 37 result.Data = repath; 38 } 39 return Json(JsonConvert.SerializeObject(result)); 40 } 41 catch (Exception) 42 { 43 return Json(JsonConvert.SerializeObject(result)); 44 } 45 }
上傳本地文件處理方法:UploadHelper.UploadFile()服務器
1 /// <summary> 2 /// 上傳文件到本地 3 /// </summary> 4 /// <param name="filename"></param> 5 /// <param name="basePath"></param> 6 /// <param name="bytes"></param> 7 /// <returns></returns> 8 public static string UploadFile(byte[] bytes,string basePath, string filename) 9 { 10 string result = ""; 11 try 12 { 13 if (bytes != null) 14 { 15 //保存文件路徑,好比:\\Images\\2020-01-01\\,這裏的basePath至關於\\Images 16 string upfilePath = basePath + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\"; //根路徑 17 //上傳到本地 ~/表示上級目錄,若是不加則表示同級目錄 18 string filePath = System.Web.HttpContext.Current.Server.MapPath("~/" + upfilePath); 19 if (!Directory.Exists(filePath)) 20 { 21 Directory.CreateDirectory(filePath); 22 } 23 //完整路徑:項目目錄\\Images\\2020-01-01\\abc.jpg 24 string fileSavePath = Path.Combine(filePath, filename); //合併成完整的文件路徑 25 26 //寫入本地 27 using (FileStream fs = new FileStream(fileSavePath, FileMode.Create)) 28 { 29 fs.Write(bytes, 0, bytes.Length); 30 fs.Close(); 31 fs.Dispose(); 32 } 33 //返回路徑:/Images/2020-01-01/abc.jpg 34 result = (upfilePath + filename).Replace("\\", "/"); 35 } 36 else 37 { 38 result = "上傳的文件信息不存在!"; 39 } 40 } 41 catch (Exception ex) 42 { 43 return ""; 44 } 45 return result; 46 }
通常向本地服務器上傳的同時,還要向cdn服務器上傳一份,請求cdn服務器接口代碼以下:網絡
1 /// <summary> 2 /// 上傳文件到遠程服務器 3 /// </summary> 4 /// <param name="bytes"></param> 5 /// <param name="basepath"></param> 6 /// <param name="filename"></param> 7 /// <returns></returns> 8 public static string PostUploadFile(byte[] bytes, string basepath, string filename) 9 { 10 string repath = ""; 11 string hosturl = ConfigurationManager.AppSettings["apihost"] ?? "https://cache.xxxxxx.com:8080/"; //遠程服務器路徑 12 try 13 { 14 var apiurl = hosturl + "api/UpLoad/ReceiveFile"; //遠程請求接口 至關於:https://cache.xxxxxx.com:8080/api/UpLoad/ReceiveFile 15 HttpClient httpClient = HttpClientFactory.GetHttpClient(); 16 string upfilePath = basepath + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\"; //保存路徑,好比:\\Images\\2020-01-01\\,basepath至關於\\Images 17 using (var multipartFormDataContent = new MultipartFormDataContent()) //MultipartFormDataContent至關於 "Content-Type": "multipart/form-data" 18 { 19 //二進制流傳輸,遠程服務器可使用: Request.Files.Get("filedata")接收 20 multipartFormDataContent.Add(new ByteArrayContent(bytes, 0, bytes.Length), "filedata", filename); 21 //遠程服務器可使用: Request["filePath"]接收 22 multipartFormDataContent.Add(new StringContent(upfilePath, Encoding.UTF8, "application/x-www-form-urlencoded"), "filePath"); 23 24 //post請求 25 var response = httpClient.PostAsync(apiurl, multipartFormDataContent).Result; 26 if (response.StatusCode == System.Net.HttpStatusCode.OK) 27 { 28 var result = response.Content.ReadAsStringAsync().Result; 29 if ((int)response.StatusCode == 200) 30 { 31 repath = (upfilePath + filename).Replace("\\", "/"); 32 } 33 } 34 } 35 return repath; 36 } 37 catch (Exception ex) 38 { 39 return repath; 40 } 41 }
接下來看看在遠程cdn服務器上如何接收本地服務器上傳過來的文件,實際上跟本地服務上傳沒多大區別。app
建立一個文件上傳服務,好比建立一個WebApI服務,建立一個文件上傳接口:/api/UpLoad/ReceiveFile,而後將該服務發佈到IIS上便可異步
而後客戶端請求路徑:https://cache.xxxxxx.com:8080/api/UpLoad/ReceiveFile
1 /// <summary> 2 /// 文件上傳服務 3 /// </summary> 4 public class UpLoadController : ApiController 5 { 6 /// <summary> 7 /// 文件接收接口 8 /// </summary> 9 /// <returns></returns> 10 [HttpPost] 11 public HttpResponseMessage ReceiveFile() 12 { 13 HttpResponseMessage response = null; 14 try 15 { 16 HttpPostedFile file = HttpContext.Current.Request.Files.Get("filedata"); //獲取文件流 17 string getfilepath = HttpContext.Current.Request["filePath"] ?? "\\Images\\"; //獲取保存路徑(不包含文件名),默認:\\Images\\ 18 var filename = file.FileName; //獲取文件名 19 20 //保存到本地的路徑,~/表示指向上級根目錄 21 string savePath = HttpContext.Current.Server.MapPath("~/" + getfilepath); 22 23 //建立文件夾 24 if (!Directory.Exists(savePath)) 25 { 26 Directory.CreateDirectory(savePath); 27 } 28 29 //保存文件到指定路徑下 30 string saveFilePath = Path.Combine(savePath, filename); 31 Stream postStream = file.InputStream; 32 using (FileStream fs = new FileStream(saveFilePath, FileMode.Create)) 33 { 34 byte[] new_b = new byte[postStream.Length]; 35 while (postStream.Read(new_b, 0, new_b.Length) != 0) 36 { 37 fs.Write(new_b, 0, new_b.Length); 38 } 39 postStream.Close(); 40 fs.Close(); 41 fs.Dispose(); 42 } 43 response = Request.CreateResponse(HttpStatusCode.OK); //成功返回200 44 } 45 catch (Exception) 46 { 47 response = Request.CreateResponse(HttpStatusCode.BadRequest); //返回400 48 } 49 return response; 50 } 51 52 }