JS25 上传文件

JS中上传文件的两种原生方法

[TOC]

使用form标签

<form>标签用于为用户输入创建HTML表单,向服务器传输数据。

表单能够包含<input>元素,比如文本字段、复选框、单选框、提交按钮等等。表单还可以包含menustextareafieldsetlegendlabel元素。

注意:form元素是块级元素,其前后会产生折行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<form id="myForm" action="http://www.w3school.com.cn/example/html/form_action.asp">
<label>姓名:
<input name="username">
</label>
<br>
<label>性别:
<input type="radio" name="gender" value="male" checked>
<input type="radio" name="gender" value="female"></label>
<br>
<label>住址:
<select name="address">
<option value="beijing" selected>北京</option>
<option value="nanjing">南京</option>
<option value="tokyo">东京</option>
</select>
</label>
<button type="submit" id="submit">提交</button>
<button type="reset">重置</button>
</form>

在一个表单里面,action规定当提交表单时向何处发送表单数据。当点击form表单内,typesubmit的按钮时,会将表单提交到action对应的地址,而点击typereset的按钮时,表单会被重置

想要阻止提交或者重置行为,需要使用e.preventDefault()

FormData对象

兼容性

除了使用<from>标签之外,还可以使用FormData对象来实现文件的上传

它是XMLHttpRequest Level 2添加的接口,浏览器兼容性如下:

利用FormData对象,可以通过添加一些键值对来模拟一系列表单空间,可以用XMLHttpRequest的send方法来提交表单。

使用FormData的最大优点是可以异步上传一个二进制文件。

FormData对象的API

  • append
  • delete
  • get
  • getAll
  • has
  • set
  • keys
  • values
  • forEach
  • entries

FormData对象的操作方法,全部在原型中,自己本身没任何的属性及方法,都需要同时实例调用

1
2
3
4
5
6
let formData = new FormData()
formData.append('user', 'zhang')
//获取
formData.get('user') //zhang
// 删除
formData.delete('user')

最常用的就是append方法:

1
formData.append(name, value, filename);

其中:

  • name,是value中数据对应的表单名称
  • value,表单的值,可以是字符串,也可以是Blob对象(包括子类型,比如File
  • filename,当一个Blob或者File作为第二个参数的时候,Blob对象的默认文件名是blobFile对象的默认文件名是该文件的名称。这个名称将指定在Content-Disposition指定

从零创建一个FormData对象

1
2
3
4
5
6
7
8
9
const formData = new FormData();

formData.append('username', 'Groucho');
formData.append('accountnum', 123456);
//数字 123456 会被立即转换成字符串 "123456"

const request = new XMLHttpRequest();
request.open('POST', 'http://foo.com/submitform.php');
request.send(formData);

FormData对象的字段类型可以是BlobFile或者string,如果它的字段类型不是Blob也不是File,则会被转换成字符串类型。

借助<input>上传

上传文件时可以直接使用获取<input>files内容来直接添加到formData里。

1
<input type="file" name="file" required />
1
2
// HTML 文件类型 input,由用户选择
formData.append('userfile', fileInputElement.files[0]);

借助Blob对象上传

也可以使用Blob对象来实现文件的上传。

一个Blob对象表示一个不可变的二进制对象,它表示的数据不一定是一个JavaScript原生格式。实际上File接口基于Blob,继承blob功能并将其扩展为支持用户系统上的文件

1
2
3
4
// Blob对象
const content = '<a id="a"><b id="b">hey!</b></a>';
const blob = new Blob([content], { type: "text/xml"});
formData.append('blob', blob, 'filename.txt');

<form>标签与formData相结合

想要构造一个包含<Form>表单数据的FormData对象,需要在创建FormData对象时指定表单的元素。

1
const formData = new FormData(someFormElement);

还以最上面的表单为例,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const url = 'http://www.w3school.com.cn/example/html/form_action.asp';

const myForm = document.querySelector('#myForm');
const submitBtn = document.querySelector('#submit');

submitBtn.addEventListener('click', function(e) {
const formData = new FormData(myForm);
formData.append('hair', 'black');

const request = new XMLHttpRequest();
request.open('POST', url);
request.send(formData);

e.preventDefault()
})

可以在创建一个包含Form表单数据的FormData对象之后和发送请求之前,附加额外的数据到FormData对象里

跨域问题

注意,通过<form>action发送表单时,是不受跨域的限制的,因为:跨域指的是跨域资源共享。当一个资源从该改资源本身所在服务器的不同的域或不同的端口请求一个资源时,资源会发起一个跨域HTTP请求。

直接使用<form>action发送表单的时候,是直接把请求交给了action里面的域,本身页面不会去管他的请求结果,后面的步骤交给了action里面的域。好比:

1
2
3
<from action="baidu.com/form/a">
<!-- your form filed -->
</from>

上面这个表单提交后,剩余的操作就交给了action里面的域baidu.com/form/a,本页面的逻辑和这个表单没啥关系,由于不关心请求的响应,所以浏览器认为是安全的。

而使用Ajax来控制form的请求的时候,页面需要知道请求的返回值,这个时候,浏览器发出跨域请求,需要获得授权才可以成功请求,否则是会拒绝的。

参考