详解前端文件上传

js实现文件上传

四种常见的post数据类型

首先文件上传首先想到的发post,当然还有其他的上传协议,我们这里只介绍发post。
post支持四种content-type:

  • application/x-www-form-urlencoded

Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。

  • multipart/form-data
Request URL:http://192.168.13.11:8080/fetch2/test/test3
Request Method:POST
Status Code:200 OK
Request Headers:
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:6010
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryk0in9FHBncyu30RT
Host:192.168.13.11:8080
Origin:null
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Request Payload
------WebKitFormBoundaryk0in9FHBncyu30RT
Content-Disposition: form-data; name="file1"; filename="main.cpp"
Content-Type: application/octet-stream


------WebKitFormBoundaryk0in9FHBncyu30RT--

首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 mutipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary 开始,紧接着内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary-- 标示结束。
RFC1867

  • application/json

application/json这个Content-Type都比较熟悉,当然也可以把json放到formData中;
RFC4657

  • text/xml

参见RFC,也比较常见。
XML-RFC

实现文件上传有2种方式

  1. 普通post请求
    该请求指的是content-type是application/json或text/xml,这种方式很简单,读取文件内容,然后上传即可,当然,有很多局限性;
  2. 利用formdata
    formdata文件上传是以二进制流形式上传,且无需写额外代码。
  • 创建formdata:
//添加form标签
<form enctype="multipart/form-data" method="post" name="fileinfo" id="myFormElement">
</form>
//创建formdata
var formElement = document.getElementById("myFormElement");
formData = new FormData(formElement);
//若有其他元素不在表单里的,可以通过append添加
formData.append("bookid",$('#bookID'.val()));
  • 使用formData发送文件

在HTML中要有一个包含了文件输入框的form元素,表单里元素的name一定要写,最终形成formData时,是以name作为key值

<form enctype="multipart/form-data" method="post" name="fileinfo">
  <label>书名:</label>
  <input type="text" name="bookname" /><br />
  <label>bookid:</label>
  <input type="text" name="bookid"  /><br />
  <label>File to stash:</label>
  <input type="file" name="file" />
</form>
<div id="output"></div>
<a href="javascript:sendForm()">Stash the file!</a>

如果直接在form里写action的话,会刷新表单,同步请求。所以用发送异步post请求方式。

function sendForm() {
  var oOutput = document.getElementById("output");
  var oData = new FormData(document.forms.namedItem("fileinfo"));

  //userName不在表单中
  oData.append("userName", "lilei");
  var oReq = new XMLHttpRequest();
  oReq.open("POST", "stash.php", true);
  oReq.onload = function(oEvent) {
    if (oReq.status == 200) {
      oOutput.innerHTML = "Uploaded!";
    } else {
      oOutput.innerHTML = "Error " + oReq.status + " occurred uploading your file.<br \/>";
    }
  };

  oReq.send(oData);
}

你还可以不借助HTML表单,直接向FormData对象中添加一个File对象或者一个Blob对象:

data.append("myfile", myBlob);

你还可以使用jQuery来发送FormData,但必须要正确的设置相关选项:

var fd = new FormData(document.getElementById("fileinfo"));
//userName不在表单中
  oData.append("userName", "lilei");
$.ajax({
  url: "stash.php",
  type: "POST",
  data: fd,
  processData: false,  // 告诉jQuery不要去处理发送的数据
  contentType: false   // 告诉jQuery不要去设置Content-Type请求头
});

MDN:使用FormData

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,314评论 19 139
  • 最近项目需要使用 Angular,对于初学 Angular 的我只能硬着头皮上了,项目中有一个需求是文件上传,磕磕...
    虽万万人吾往矣阅读 18,400评论 3 20
  • /*----------------- 01 POST上传单个文件 -----------------*/ 重点:...
    蓝心儿的蓝色之旅阅读 6,725评论 0 5
  • 整体Retrofit内容如下: 1、Retrofit解析1之前哨站——理解RESTful2、Retrofit解析2...
    隔壁老李头阅读 15,246评论 4 39
  • iOS开发系列--网络开发 概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博、微信等,这些应用本身可...
    lichengjin阅读 9,112评论 2 7