XMLHttpRequest

基本格式,readyState,HTTP头部,超时,判断响应的MIME类型,进度事件,跨源(跨域),预检请求,凭据请求

基本格式:

let xhr = new XMLHttpRequest()
【1】
xhr.open(method, url, async)//method: string, url: string, async?: boolen是否异步
//如果method是get,参数要加在url后,post请求则可以写在send()里
xhr.send(null)//这里必须发送数据,如果没有,就为null(必须)

如果是同步的:
if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
  console.log(xhr.responseText.slice(0, 20));
} else {
  console.log('failed', xhr.status);
}
如果是异步的就需要用onreadystatechange监视readyState的变化,从而在请求完成之后获取结果
readyState: number
  0: 未初始化,未open
  1: 已打开,open()
  2: 已发送,send()
  3: 接受中,以有部分响应,可以使用部分结果
  4: 完成,已收到所有响应
应该在【1】出添加如下代码
xhr.onreadystatechange = function () {
  console.log('readyState: ', xhr.readyState);
  if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
    console.log(xhr.responseText.slice(0, 20));
  } else {
    console.log('failed', xhr.status);
  }
}

HTTP头部

浏览器会自动发送一些请求头,如Accept,Host等,若需要发送额外的请求头,需要用到xhr.setRequestHeader(headerName: string, keaderValue: string),在open()和send()之间使用。读取请求头的两种方法:
xhr.getResponseHeader(headerName: string)xhr.getAllResponseHeaders()

超时timeout与ontimeout

xhr.onreadystateChange = function() {
  /*
  之所以要try/catch是因为即时超时也会走到xhr.readyState=4这一步,
  只是在超时后访问xhr.status会发送错误
  */
  if (xhr.readySate != 4) return
  try {
    if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
      console.log(xhr.responseText.slice(0, 20));
    } else {
      console.log('failed', xhr.status);
    }
  } catch(e) {...}
}
xhr.open(..., true)
xhr.timeout = 1000  //1000ms未响应是为超时
xhr.ontimeout = function() {...}  //监听超时的函数
xhr.send()

判断响应的MIME类型

响应返回的MIME类型决定了XHR的处理方式。如果浏览器返回的是XML,而响应头的MIME类型默认或者被设置成text/plain结果就会导致responseXML获取为null,即被错误的方式处理了。

xhr.open(...)
xhr.overrideMinmeType('text/xml')
xhr.send(...)

进度事件

名字 什么时候触发
loadstart 接收到响应返回的第一个字节的时候
progress 在接收响应期间反复触发,进度条
error 请求错误时
abort 调用xhr.abort()终止请求时
load 成功完成响应接收时
loadend 完成响应时,成不成功无所谓,abort,error之后也会触发;在load之后

progress的两个常用属性:position,totalSzie;都是number。已经接收的大小,总的大小

//异步请求上述功能才有意义
xhr.onprogress = fucntion (event) {
  console.log('已经接收:', event.position / event.totalSize * 100, '%')
}

跨源(跨域)

处于安全,XHR只能访问与发起请求的页面在同一域内的资源。同一域:协议,域名/IP,端口都相同。但是也允许合法跨域。
对于常规的请求如get, post等,都会自带一个text/plain类型的请求头叫Origin,值为发起请求的页面的源(域)。
Origin: http://wwww.baidu.com
服务器端如果允许这个源访问的话,就要发送请求头:
'Access-Control-Allow-Origin': 'http://www.baidu.com'
如果全部都允许的话可以'Access-Control-Allow-Origin': '*'
以expressJs为例:

app.all('*', function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');  //就是这句
  res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
  res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
  if (req.method == 'OPTIONS') {
    res.send(200);
  } else next();
});

为了安全:前面提到的setRequestHeader()可以设置请求头,跨域请求的话就不允许使用这个方法了;也不能发送和接收cookie,getAllResponseHeaders()返回值也为空。
所以不论同域还是跨域时都建议:访问本地资源用相对路径,远程资源用绝对路径,一来区分使用场景,二来避免出现访问本地资源时头部/cookie使用受限问题

预检请求

这是个服务器验证机制,是自动的,知道就行
第一次向某地址发送请求之前,浏览器会以options方法向该地址发送一个请求,请求的参数包含:

  1. Origin: string 如:'http://www.baidu.com'
  2. Access-Control-Request-Headers: string 如:'Content-Type, Content-Length'
  3. Access-Control-Request-Methods: string 如:'DELETE, PUT, UPDATE'

通过这个请求来检测这个源允许哪些源来请求,允许哪些请求头,请求方法。

而服务器端的跨域处理会向浏览器发送允许的类型,与浏览器沟通,后端代码就如上面那个一样,浏览器收到的也是

凭据请求

暂时不懂有什么用

前端:
默认情况下,跨域请求不提供凭据(即cookie,HTTP认证和客户端SSL证书)。但是可以通过xhr.withCredentials = true来告诉服务端"我"会发送凭据

后端:
如果允许带凭据请求,就要满足以下几点:

  1. Access-Control-Allow-Origin不能为*
  2. Access-Control-Allow-Credentials为true

上面前后端两个有任何一个不满足都会触发xhr.onerror
完整&简略的写法

前端:
xhr.open(...)
xhr.withCredentials = true  //【1】会发送凭据
xhr.send(...)

后端:(expressJs为例)
/* app.js */ 跨域处理
app.all('*', (req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'http://xxx.com')  //【2】此处不能为 *
})
/* index.js */路由
这个接口允许凭据请求
index.get('/allowCredential', (req, res, next) => {
  res.header("Access-Control-Allow-Credentials", true)  //【3】允许发送凭据请求
  res.send(...)
})

posted on 2022-02-24 23:54  In-6026  阅读(70)  评论(0)    收藏  举报

导航