web api 如何通过接收文件流的方式,接收客户端及前端上传的文件
服务端接收文件流代码:
public async Task<HttpResponseMessage> ReceiveFileByStream() { var stream = HttpContext.Current.Request.InputStream; if (stream.Length > 0) { var absolutePath = HttpContext.Current.Request.MapPath("/img/"); if (!Directory.Exists(absolutePath)) { Directory.CreateDirectory(absolutePath); } var fileType = ""; var bytes = new byte[stream.Length]; stream.Read(bytes, 0, bytes.Length); //前两个字节代表文件类型,这里以 JPG 类型为例 var bs = bytes[0].ToString() + bytes[1].ToString(); if (bs.Equals("255216")) { fileType = ".jpg"; } var path = absolutePath + Guid.NewGuid() + fileType; await Task.Run(() => { using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) { fs.Write(bytes, 0, bytes.Length); } }); return Request.CreateResponse(HttpStatusCode.OK, "上传成功!"); } else { return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "没有文件耶,哥们!"); } }
客户端上传文件流代码:
HttpClient
static string TestHttpClientUpload() { var resultStr = string.Empty; HttpClient client = new HttpClient(); client.BaseAddress = new Uri("http://192.168.20.15:57895"); string apiUrl = "api/upload/ReceiveFileByStream";
string path = @"C:\Users\xxxx\Desktop\woman.jpg"; FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
HttpContent content = new StreamContent(fs); var result = client.PostAsync(apiUrl, content).Result; fs.Dispose(); resultStr = result.Content.ReadAsStringAsync().Result; return resultStr;//上传成功 }
HttpWebRequest
static string TestHttpWebRequestUpload() { var resultStr = string.Empty; string url = "http://192.168.20.15:57895/api/upload/ReceiveFileByStream"; HttpWebRequest request = WebRequest.CreateHttp(url); request.Method = "post"; string path = @"C:\Users\xxxx\Desktop\woman.jpg"; FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read); var requestStream = request.GetRequestStream(); fs.CopyTo(requestStream); fs.Dispose(); requestStream.Dispose(); var result = request.GetResponseAsync().Result; var responseStream = result.GetResponseStream(); using (StreamReader sm = new StreamReader(responseStream)) { resultStr = sm.ReadToEnd(); } return resultStr;//上传成功 }
前端上传文件:
<div> <span>Form表单上传单个文件</span><br /> <form id="myForm1" enctype="multipart/form-data" method="post" action="http://192.168.20.15:57895/api/upload/ReceiveFileByStream"> <input type="file" name="myFile" /> <input type="submit" value="submit提交" /> </form> </div>
上面三种方式,客户端没有问题,但是前端这样上传是有问题的,因为在文件流开头还有其他东西:
用一段代码测试:
//这里的 255 是 255216 里面的 255, 从 255 所在的位置开始才是文件的字节数据 var index = bytes.ToList().IndexOf(255); var str = Encoding.UTF8.GetString(bytes, 0, index); Trace.WriteLine(str);
这就是HTTP请求自带的,打开浏览器,F12,可以看到:
那么,如何成功的躲避这一段字节呢?
答案是 : 利用 Ajax 提交表单
<div> <form id="myForm4"> <input type="file" id="myFile" /> <input type="button" value="AJAX提交图片" onclick="uploadFile()" /> </form> </div>
function uploadFile() { var url = "http://192.168.20.15:57895/api/upload/ReceiveFileByStream"; var data = $("#myFile")[0].files[0]; $.ajax({ url: url, data: data, type: "post", processData: false,//表示提交的时候不会序列化 data,而是直接使用 data,默认为 true contentType: false,//表示不要去设置Content-Type请求头 cache: false,//设置为 false 将不会从浏览器缓存中加载请求信息。 success: function () { } }); }
但是,这样提交在跨域的时候,会有一次 OPTIONS 请求
下面那次请求才是 POST 请求,至于为什么会有一次 OPTIONS 请求,大家可以自行百度,这里就不说了.
那么如何成功的避免这次 OPTIONS 请求呢?
答案就是 : Ajax 请求的时候, 不设置 contentType 属性!
function uploadFile() { var url = "http://192.168.20.15:57895/api/upload/ReceiveFileByStream"; var data = $("#myFile")[0].files[0]; $.ajax({ url: url, data: data, type: "post", processData: false,//表示提交的时候不会序列化 data,而是直接使用 data,默认为 true cache: false,//设置为 false 将不会从浏览器缓存中加载请求信息。 success: function () { } }); }
收工!