ajax请求可以做到在没有重新加载页面下,进行数据的更新例如做到:
也是前端用于发起网络请求的比较好的主流方式,ajax请求主要包括两种
XML和fetch,XML可能接触的比较多,下面主要学习fetch请求。
fetch() 方法是一种现代通用的方法,那么我们就从它开始吧。旧版本的浏览器不支持它(可以 polyfill),但是它在现代浏览器中的支持情况很好。
let promise = fetch(url,[options])
url:要访问的url
options:可选参数:method、header等
获取响应有两个阶段:
第一阶段, 当服务器发送了响应头(response header),fetch 返回的 promise 就使用内建的 Response class 对象来对响应头进行解析。
检查响应头,检查http状态确定请求是否成功,当前还没有响应体
如果 fetch 无法建立一个 HTTP 请求,例如网络问题,亦或是请求的网址不存在,那么 promise 就会 reject。异常的 HTTP 状态,例如 404 或 500,不会导致出现 error。
我们可以在 response 的属性中看到 HTTP 状态:
status —— HTTP 状态码,例如 200。
ok —— 布尔值,如果 HTTP 状态码为 200-299,则为 true。
let response = await fetch(url);
if(response.ok){
let json = await response.json();
}else{
alert("HTTP-ERROR" + response.status)
}
第二阶段, 为了获取 response body,我们需要使用一个其他的方法调用。
Response 提供了多种基于 promise 的方法,来以不同的格式访问 body:
response.text() —— 读取 response,并以文本形式返回 response,
response.json() —— 将 response 解析为 JSON 格式,
response.formData() —— 以 FormData 对象(在 下一章 有解释)的形式返回 response,
response.blob() —— 以 Blob(具有类型的二进制数据)形式返回 response,
response.arrayBuffer() —— 以 ArrayBuffer(低级别的二进制数据)形式返回 response,
另外,response.body 是 ReadableStream 对象,它允许你逐块读取 body,我们稍后会用一个例子解释它。
如果要创建一个post请求,
let user = {
name: 'John',
surname: 'Smith'
};
let response = await fetch('/article/fetch/post/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(user)
});
let result = await response.json();
alert(result.message);
典型的fetch请求由两个await调用执行
let response = await fetch(url,options);
let result = await response.json();
//或者以promise
fetch(url,options)
.then(response => response.json())
.then(result => )
FormData对象是表示HTML表单数据的对象,
FormData 的特殊之处在于网络方法(network methods),例如 fetch 可以接受一个 FormData 对象作为 body。它会被编码并发送出去,带有 Content-Type: multipart/form-data。
从服务器角度来看,它就像是一个普通的表单提交。
FormData对象用于捕获HTML表单,并使用fetch或其他网络方法提交
fetch 方法允许去跟踪 下载 进度。
请注意:到目前为止,fetch 方法无法跟踪 上传 进度。对于这个目的,请使用 XMLHttpRequest,我们在后面章节会讲到。
与 response.text(),response.json() 和其他方法同,response.body 给予了对进度读取的完全控制,我们可以随时计算下载了多少。
正如我们所知道的,fetch 返回一个 promise。JavaScript 通常并没有“中止” promise 的概念。那么我们怎样才能取消一个正在执行的 fetch 呢?例如,如果用户在我们网站上的操作表明不再需要某个执行中的 fetch。
为此有一个特殊的内建对象:AbortController。它不仅可以中止 fetch,还可以中止其他异步任务
let controller = new AbortController();
但是有价值的是,fetch 知道如何与 AbortController 对象一起工作。它们是集成在一起的。
为了能够取消 fetch,请将 AbortController 的 signal 属性作为 fetch 的一个可选参数(option)进行传递:
let controller = new AbortController();
fetch(url,{
signal:controller.signal
});
controller.abort();
fetch 方法知道如何与 AbortController 一起工作。它会监听 signal 上的 abort 事件。
现在,想要中止 fetch,调用 controller.abort() 即可。
当一个 fetch 被中止,它的 promise 就会以一个 error AbortError reject,因此我们应该对其进行处理,例如在 try…catch 中。
et controller = new AbortController();
setTimeout(()=> controller.abort(),1000);
try {
let response = await fetch('/article/fetch-abort/demo/hang',{
signal:controller.signal
});
} catch(err) {
if(err.name == 'AbortError'){
alert("Aborted");
}else{
throw err;
}
}
AbortController 是可伸缩的。它允许一次取消多个 fetch。
let urls = [];
let controller = new AbortController();
let fetchJobs = urls.map(url => fetch(url,{
signal:controller.signal
}));
let results = await Promise.all(fetchJobs);
如果我们向另一个网站发送 fetch 请求,则该请求可能会失败.
同源:协议、端口、域名一致
跨源请求,就是三者不是完全一致的,发送到其他域的请求,就需要来自远程端的特殊leader
CORS:跨资源共享(Cross-Origin Resource Shering)
有两种类型的跨源请求:
1、安全类型
2、所有其他请求
安全的方法:GET,POST 或 HEAD
安全的 header —— 仅允许自定义下列 header:
Accept,
Accept-Language,
Content-Language,
Content-Type 的值为 application/x-www-form-urlencoded,multipart/form-data 或 text/plain。
本质区别在于,可以使用 form或 script进行安全请求,而无需任何其他特殊方法。
当我们尝试发送一个非安全请求时,浏览器会发送一个特殊的“预检(preflight)”请求到服务器 —— 询问服务器,你接受此类跨源请求吗?
并且,除非服务器明确通过 header 进行确认,否则非安全请求不会被发送。
如果一个请求是跨源的,浏览器始终会向其添加 Origin header。
例如,如果我们从 https://javascript.info/page 请求 https://anywhere.com/request,请求的 header 将如下所示:
GET /request
Host: anywhere.com
Origin: https://javascript.info
...
正如你所看到的,Origin 包含了确切的源(domain/protocol/port),没有路径(path)。
服务器可以检查 Origin,如果同意接受这样的请求,就会在响应中添加一个特殊的 header Access-Control-Allow-Origin
浏览器在这里扮演受被信任的中间人的角色:
它确保发送的跨源请求带有正确的 Origin。
它检查响应中的许可 Access-Control-Allow-Origin,如果存在,则允许 JavaScript 访问响应,否则将失败并报错。
200 OK
Content-Type:text/html; charset=UTF-8
Access-Control-Allow-Origin: https://javascript.info
对于跨源请求,默认情况下,JavaScript 只能访问“安全的” response header:
“非安全”请求
我们可以使用任何 HTTP 方法:不仅仅是 GET/POST,也可以是 PATCH,DELETE 及其他。
预检请求使用 OPTIONS 方法,它没有 body,但是有三个 header:
服务器返回:
当发起一个非安全请求
let response = await fetch('https://site.com/service.json', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'API-Key': 'secret'
}
});
Step 1 预检请求(preflight request)
在发送我们的请求前,浏览器会自己发送如下所示的预检请求:
OPTIONS /service.json
Host: site.com
Origin: https://javascript.info
Access-Control-Request-Method: PATCH
Access-Control-Request-Headers: Content-Type,API-Key
Step 2 预检响应(preflight response)
服务应响应状态 200 和 header:
Access-Control-Allow-Origin: https://javascript.info
Access-Control-Allow-Methods: PATCH
Access-Control-Allow-Headers: Content-Type,API-Key。
Step 3 实际请求(actual request)
预检成功后,浏览器现在发出主请求。这里的过程与安全请求的过程相同。
PATCH /service.json
Host: site.com
Content-Type: application/json
API-Key: secret
Origin: https://javascript.info
主请求具有 Origin header(因为它是跨源的):
Step 4 实际响应(actual response)
服务器不应该忘记在主响应中添加 Access-Control-Allow-Origin。成功的预检并不能免除此要求:
Access-Control-Allow-Origin: https://javascript.info