二十四、网络请求与远程资源

在这里插入图片描述

XML是过时的web规范产物,可以仅作了解,实际开发中应尽可能使用fetch()等

1.XMLHttpRequest对象

const xhr = new XMLHttpRequest();

使用XHR

const xhr = new XMLHttpRequest();
// 1.打开一个请求
xhr.open(method, url, isAsync); // 请求方法,请求路径,是否同步请求
// xhr.open('get', 'example.php', false);
// 2.发送一个请求
xhr.send(data); // 如果不需要发送数据,就send(null);
// 3.同步请求会在服务器响应后再继续执行,收到请求后,xhr对象上会填充如下属性
/**
responseText: 作为响应体的文本
responseXML: 如果相应内容为“text/html”或者“application/xml”, 则包含响应数据的XML DOM文档
status: 响应HTTP的状态
statusText: 响应HTTP的描述。
*/

同步请求:

/******** demo ************/
xhr.open("get", "example.txt", false);
xhr.send(null);
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
 alert(xhr.responseText);
} else {
 alert("Request was unsuccessful: " + xhr.status);
}

异步请求:监听XMR对象上的readyState属性值的变化

readStaty属性值说明
0未初始化,还没调用open方法
1已打开,调用open(), 未调用send()
2已发送, 调用send(), 未响应
3接受中, 收到了部分响应
4完成,接受到了全部响应
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
	 if (xhr.readyState == 4) {
		 if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
		 	alert(xhr.responseText);
		 } else {
		 	alert("Request was unsuccessful: " + xhr.status);
		 }
	 }
};
xhr.open("get", "example.txt", true);
xhr.send(null); 

// 如果想要取消异步请求,可以调用xhr.abort();

HTTP头部

XHR请求头部字段

字段含义
Accept浏览器可以处理的内容类型
Accept-Charset浏览器可以现实的字符集
Accept-Encoding浏览器可以处理的压缩编码类型
Accept-Language浏览器使用的语言
Connection浏览器和服务器连接的类型
Cookiecookie数据
Host发送请求的页面所在的域
Referer发送请求的页面的url
User-Agent浏览器的用户代理字符串

可以通过setRequestHeader(key, val)自定义请求头字段,必须在open()调用之后,send()调用之前调用。
获取响应头部的方法getResponseHeader(key)getAllResponseHeader()

GET

发送 GET 请求最常见的一个错误是查询字符串格式不对。查询字符串中的每个名和值都必须使用encodeURIComponent()编码

POST

POST 请求相比 GET 请求要占用更多资源。从性能方面说,发送相同数量的数据,
GET 请求比 POST 请求要快两倍

XMLHttpRequest Level2

FormData类型

xhr.send(formdata); // 不需要显示地设置头部

let data = new FormData();
data.append('name', 'coder');
超时

xhr对象上添加了timeout属性,用于设置超时时间

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
	 if (xhr.readyState == 4) {
		 try {
			 if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
				 alert(xhr.responseText);
			 } else {
				 alert("Request was unsuccessful: " + xhr.status);
			 }
		 } catch (ex) {
		 // 假设由 ontimeout 处理
		 }
	 }
};
xhr.open("get", "timeout.php", true);
xhr.timeout = 1000; // 设置 1 秒超时
xhr.ontimeout = function() {
 alert("Request did not return in a second.");
};
xhr.send(null);
overrideMimeType()方法

用于重写XHR响应的MIME类型,必须在send()之前调用

let xhr = new XMLHttpRequest();
xhr.open("get", "text.php", true);
xhr.overrideMimeType("text/xml");
xhr.send(null); 

2.进度事件

这些事件最初只针对xhr,现在也推广到其他api了

事件含义
loadstart在接收到响应的第一个字节时触发
progress在接受响应期间反复触发
error在请求出错时触发
abort调用abort()时
load在成功接受完响应时触发
loadend在通信完成时触发,且在error、abort、load之后

load事件

firefox在实现xhr时,增加load事件代替readystatechange事件, event.target=== xhr

let xhr = new XMLHttpRequest();
xhr.onload = function() {
	 if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
	 	alert(xhr.responseText);
	 } else {
	 	alert("Request was unsuccessful: " + xhr.status);
	 }
};
xhr.open("get", "altevents.php", true);
xhr.send(null); 

progress事件

onprogress事件接收到event对象,其target属性为XHR对象,且包含三个额外属性
lengthComputable: 布尔值,表示进度信息是否可用
position:接收到的字节数
totalSize: 响应的Content-Length头部定义的总字节数
必须在调用open()之前添加onprogress事件

let xhr = new XMLHttpRequest();
xhr.onload = function(event) {
	 if ((xhr.status >= 200 && xhr.status < 300) ||
	 xhr.status == 304) {
	 	alert(xhr.responseText);
	 } else {
	 	alert("Request was unsuccessful: " + xhr.status);
	 }
};
xhr.onprogress = function(event) {
	 let divStatus = document.getElementById("status");
	 if (event.lengthComputable) {
	 	divStatus.innerHTML = "Received " + event.position + " of " + event.totalSize + " bytes";
	 }
};
xhr.open("get", "altevents.php", true);
xhr.send(null); 

3.跨源资源共享

受同源策略限制,XHR只能访问与发起请求的页面同一个域内的资源。
对于简单请求,请求头部有个Origin字段,包含请求页面的源,如果服务器决定响应请求,响应头应包含Access-Control-Allow-Origin(此行为会被自动触发)
跨域XHR对象还有一些额外的限制

  • 不能使用setRequestHeader()自定义头部字段
  • 不能发送和接受cookie
  • getAllResponseHeaders()始终返回空字符串

预检请求OPTIONS

请求头字段

字段含义
Origin
Access-Control-Request-Method请求希望使用的方法
Access-Control-Request-Headers请求可以接受的头部字段

响应头

字段含义
Access-Control-Allow-Origin
Access-Control-Allow-Methods允许的方法
Access-Control-Allow-Headers允许的头部字段
Access-Control-Max-Age缓存预检请求的秒数

凭据请求

默认情况下,跨域请求不会提供凭据
可以通过将xhr对象的withCredentials属性设为true来表明会发送凭据请求。此时响应头中应当包含Access-Control-Allow-Credentials:true

4.代替性跨源技术

图片探测

任何页面都可以跨域加载图片,而不用担心限制,
缺点是:只能发送get请求,无法获取服务器的相应数据

let img = new Image();
img.onload = img.onerror = function() {
 alert("Done!");
};
img.src = "http://www.example.com/test?name=Nicholas"; 

JSONP

JSONP格式包括回调数据两部分,其调用是通过动态创建<script>标签,并未src属性设置跨域URL实现的。

function handleResponse(response) {
 console.log(`You're at IP address ${response.ip}, which is in ${response.city}, ${response.region_name}`);
}
let script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);

仍有一个缺点:不好确定请求是否失败,可以通过设置定时器来决定是否放弃请求。

5.fetch API

fetch api能够完成xhr对象的所有任务,且必须是异步的。

基本用法

1.分派请求

fetch(url)接受一个参数url,返回一个promise,期约解决为response对象

2.读取响应

text()取得纯文本格式内容
json()取得json格式内容

fetch(url).then(res => res.json() || res.text())
3处理状态码和请求失败
  • 通过 Response 的 status(状态码)和 statusText(状态文本)属性检查响应状态
  • 跟随重定向时,响应对象的 redirected 属性会被设置为 true
  • 状态码非 200~299 时检查 Response 对象的 ok 属性:
  • 可以通过 url 属性检查通过 fetch()发送请求时使用的完整 URL
4.自定义选项

fetch()只有一个参数数,默认发送get请求,其他请求需要传入第二个配置项参数
配置项参数大致如body/header/method/等

常见的Fetch请求模式

发送json数据
let payload = JSON.stringify({
 foo: 'bar'
});
let jsonHeaders = new Headers({
 'Content-Type': 'application/json'
});
fetch('/send-me-json', {
 method: 'POST', // 发送请求体时必须使用一种 HTTP 方法
 body: payload,
 headers: jsonHeaders
}); 
在请求体中发送参数
let payload = 'foo=bar&baz=qux';
let paramHeaders = new Headers({
 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
});
fetch('/send-me-params', {
 method: 'POST', // 发送请求体时必须使用一种 HTTP 方法
 body: payload,
 headers: paramHeaders
});
发送文件
// 发送单个文件
let imageFormData = new FormData();
let imageInput = document.querySelector("input[type='file']");
imageFormData.append('image', imageInput.files[0]);
fetch('/img-upload', {
 method: 'POST',
 body: imageFormData
}); 

// 发送多个文件
let imageFormData = new FormData();
let imageInput = document.querySelector("input[type='file'][multiple]");
for (let i = 0; i < imageInput.files.length; ++i) {
 imageFormData.append('image', imageInput.files[i]);
}
fetch('/img-upload', {
 method: 'POST',
 body: imageFormData
}); 
加载Blob文件
const imageElement = document.querySelector('img');
fetch('my-image.png')
 .then((response) => response.blob())
 .then((blob) => {
 imageElement.src = URL.createObjectURL(blob);
 });
发送跨域请求

发送跨域请求需要添加CORS头部;若不需要响应,也可以发送no-cors请求,用于发送探测请求。

fetch('//cross-origin.com', { method: 'no-cors' })
 .then((response) => console.log(response.type));
// opaque
中断请求
let abortController = new AbortController();
fetch('wikipedia.zip', { signal: abortController.signal })
 .catch(() => console.log('aborted!');
// 10 毫秒后中断请求
setTimeout(() => abortController.abort(), 10);

Headers对象

每个外发的 Request 实例都包含一个空的Headers 实例,可以通过 Request.prototype.headers 访问,使用 new Headers()也可以创建一个新实例

与Map相似

都有 get()、set()、has()和 delete()等实例方法

独特之处

初始化时,可以使用键值对的对象;
append()添加键值对

头部护卫
护 卫适用情形限 制
none在通过构造函数创建 Headers 实例时激活
request在通过构造函数初始化 Request对象,且 mode值为非 no-cors 时激活不允许修改禁止修改的头部(参见 MDN 文档中的 forbidden header name 词条)
request-no-cors在通过构造函数初始化 Request对象,且 mode值为 no-cors 时激活不允许修改非简单头部(参见 MDN 文档中的simple header 词条)
response在通过构造函数初始化 Response 对象时激活不允许修改禁止修改的响应头部(参见 MDN 文档中的 forbidden response header name 词条)
immutable在通过 error()或 redirect()静态方法初始化 Response 对象时激活不允许修改任何头部

Request对象

创建Request对象

需要传入一个参数url或者一个Request对象,也可以传入第二个配置参数,配置项同fetch()的第二个参数

克隆Request对象

req.clone()
new Request(requestobj)

fetch()中可以直接传入一个Request对象

Response对象

  • 创建 初始化时不需要参数, 可以接受一个body参数,还可以接受一个配置参数(能配置headers/status/statusText)
  • 读取响应状态
属 性
headers响应包含的 Headers 对象
ok布尔值,表示 HTTP 状态码的含义。200~299 的状态码返回 true,其他状态码返回 false
redirected布尔值,表示响应是否至少经过一次重定向
status整数,表示响应的 HTTP 状态码
statusText字符串,包含对 HTTP 状态码的正式描述。这个值派生自可选的 HTTP Reason-Phrase 字段,因此如果服务器以 Reason-Phrase 为由拒绝响应,这个字段可能是空字符串
type字符串,包含响应类型。可能是下列字符串值之一
  1. basic:表示标准的同源响应
    1. cors:表示标准的跨源响应
      1. error:表示响应对象是通过 Response.error()创建的
        1. opaque:表示 no-cors 的 fetch()返回的跨源响应
          1. opaqueredirect:表示对 redirect 设置为 manual 的请求的响应
url包含响应 URL 的字符串。对于重定向响应,这是最终的 URL,非重定向响应就是它产生的
  • 克隆Response对象
    r1.clone()

Request、Response 及 Body 混入

  • body.text()
  • body.json()
  • body.formData()
  • body.arrayBuffer()
  • body.blob()

6.Beacon API

许多分析工具需要在页面生命周期尽可能晚点的时候想服务器发送遥测或者分析数据,理想情况是在unload事件触发时发送,但是在 unload 事件处理程序中创建的任何异步请求都会被浏览器取消
navigator 对象增加了一个sendBeacon()方法。这个简单的方法接收一个 URL 和一个数据有效载荷参数,并会发送一个 POST请求。可选的数据有效载荷参数有 ArrayBufferView、Blob、DOMString、FormData 实例。如果请求成功进入了最终要发送的任务队列,则这个方法返回 true,否则返回 false。

7.Web Socket

目标是通过一个长时连接实现与服务器全双工、双向的通信。在 JavaScript中创建 Web Socket 时,一个 HTTP 请求会发送到服务器以初始化连接。服务器响应后,连接使用 HTTP的Upgrade头部从 HTTP 协议切换到 Web Socket 协议。这意味着 Web Socket 不能通过标准 HTTP 服务器实现,而必须使用支持该协议的专有服务器。

API

创建时需要传入一个连接的url, 同源策略不适用于websocket

let socket = new WebSocket("ws://www.example.com/server.php");

与 XHR 类似,WebSocket 也有一个readyState 属性表示当前状态

状态
WebSocket.OPENING (0)正在建立连接
WebSocket.OPEN(1)已经建立连接
WebSocket.CLOSING (2)正在关闭
WebSocket.CLOSE (3)已关闭

任何时候都可以调用 close()方法关闭 Web Socket 连接

发送和接受数据
  • 使用 send()方法并传入一个字符串、ArrayBuffer 或 Blob
  • 服务器向客户端发送消息时,WebSocket 对象上会触发 message 事件。这个 message 事件与其他消息协议类似,可以通过event.data 属性访问到有效载荷
let socket = new WebSocket("ws://www.example.com/server.php");
let stringData = "Hello world!";
let arrayBufferData = Uint8Array.from(['f', 'o', 'o']);
let blobData = new Blob(['f', 'o', 'o']);
socket.send(stringData);
socket.send(arrayBufferData.buffer);
socket.send(blobData);

socket.onmessage = function(event) {
 let data = event.data;
 // 对数据执行某些操作
};
其他事件
事件说明
open连接成功建立时触发
error发生错误时触发,连接无法续存
close关闭时触发,唯一有额外信息的参数,wasClean/code/reason
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乘风xs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值