07-AJAX

nobility 发布于 2021-01-10 1228 次阅读


AJAX

XMLHttpRequest

构造方法

没有任何参数,只是生成了一个实例

实例属性

状态
属性名 描述
XMLHttpRequest.readyState 返回一个整数,表示实例对象的状态;0=实例生成但未调用open()方法、1=open()方法调用但未调用send()方法,可使用setRequestHeader()方法设置请求头信息、2=send()方法已经调用并且收到了响应头、3=正在接收传来的响应体,若responseType属性等于text或者空字符串说明responseText属性就会包含已经收到的部分信息、4=响应体全部接收完毕或接收失败
XMLHttpRequest.timeout 设置请求超时时间,以毫秒为单位
响应行
属性名 描述
XMLHttpRequest.status 返回响应状态码,请求发出之前是0
XMLHttpRequest.statusText 返回响应状态信息
响应体
属性名 描述
XMLHttpRequest.response 返回成功的响应体,若失败或成功但是数据不完整该属性值为null,但是若responseType属性等于text或者空字符串,在请求未结束前包含部分请求体,是只读属性
XMLHttpRequest.responseType 是一个字符串,表示服务器返回的数据类型,在调用open()方法后send()方法之前可设置这个属性告诉服务器返回指定数据类型;空字符串和text=字符串、arraybuffer=ArrayBuffer对象二进制数组、blob=Blob对象二进制对象、document=Document对象文档对象、json=JSON对象
XMLHttpRequest.responseText 返回服务器接收的字符串,若responseType属性等于text或者空字符串,在请求未结束前包含部分请求体,是只读属性
XMLHttpRequest.responseXML 返回服务器接收的HTML或XML,若不能被解析成XML或 HTML则为null(部分数据不能被正确解析所以也为null),是只读属性
XMLHttpRequest.responseURL 返回返回响应的服务器URL,这个属性不一定和请求的服务器URL一致,因为请求可以在服务端跳转,此外还会将URL中的锚点剔除
XMLHttpRequest.withCredentials 布尔值,表示跨域请求时是否发送请求域的Cookie,默认为false
监听函数

所有XMLHttpRequest的监听事件绑定,都必须在send()方法调用之前

属性名 描述
XMLHttpRequest.onreadystatechange readystatechange事件的监听函数,readyState属性变化时触发
XMLHttpRequestEventTarget.ontimeout timeout事件的监听函数,请求超时触发
XMLHttpRequest.upload 用AJAX上传文件时,该属性是一个拥有一系列监控进度事件的对象,可监控上传进度和状态
XMLHttpRequest.onprogress progress事件的监听函数,正在发送和加载数据持续触发
XMLHttpRequest.onabort abort事件的监听函数,用户主动触发(即调用调用abort()方法),因为错误中止不会触发
XMLHttpRequest.onerror error事件的监听函数,因为错误导致中止时触发
XMLHttpRequest.onload load事件的监听函数,请求成功时触发
XMLHttpRequest.onloadstart loadstart事件的监听函数,请求发出时触发
XMLHttpRequest.onloadend loadend事件的监听函数,请求完成时触发,不管成功或失败

实例方法

方法名 描述
XMLHttpRequest.open(method,URI,[flag,user,passwd]) 设置请求行(method需要大写的请求方法字符串,URI是相对路径时是相对与当前页面的URL)、是否是异步请求(默认false),身份认证信息(默认空字符串,一般用不着)
XMLHttpRequest.send(data) 设置发送的请求体并开始发送请求,可以是字符串、FormDataArrayBufferViewBlob
XMLHttpRequest.abort() 终止发出的请求,readyState变为4,status变为0
XMLHttpRequest.setRequestHeader(key,value) 设置请求头信息
XMLHttpRequest.overrideMimeType(MIME) 覆盖服务器返回的MIME类型,不过最好还是使用responseType告诉服务器要使用的什么类型,若服务器无法返回指定类型时才会使用该方法进行覆盖;必须在send()方法之前调用
XMLHttpRequest.getResponseHeader(lab) 获取指定响应头,若不存在返回null,若有多个相同的头会将多个头的值连成字符串并用逗号空格分隔
XMLHttpRequest.getAllResponseHeaders() 获取所有响应头

AJAX示例

步骤:

  1. 创建XMLHttpRequest实例
  2. 发出HTTP请求
  3. 接收服务器传回数据
  4. 更新网页数据
let xhr = new XMLHttpRequest(); //创建XMLHttpRequest实例
xhr.onreadystatechange=function(){  //设置AJAX状态监听函数
  if(xhr.readyState === 4){ //若AJAX处于结束状态
    if(xhr.status === 200){ //若响应状态码是200
      console.log(xhr.response);  //打印请求体数据
    }else{
      console.log(xhr.statusText);  //否则打印请求状态信息
    }
  }
}
xhr.open("GET","/path",true); //设置请求头
xhr.send(); //发出请求,未设置请求体

文件上传

ArrayBuffer对象

表示一段二进制数据,用来模拟内存里面的数据,通过这个对象,JavaScript可以读写二进制数据

构造方法
  • 接收一个参数,表示这段二进制数据占用多少字节
实例属性
属性名 描述
ArrayBuffer.prototype.byteLength 返回所分配的内存区域的字节长度
实例方法
属性名 描述
ArrayBuffer.prototype.slice(start[,end]) 返回[start,end)[start,end)的子ArrayBuffer对象

Blob对象

表示一个二进制文件的数据内容,它与 ArrayBuffer的区别在于,它用于操作二进制文件,而 ArrayBuffer用于操作内存

构造方法
参数 描述
第一个参数(必须) 数组,成员是二进制对象或字符串,表示新生成的Blob实例对象的内容
第二个参数(可选) 是一个配置对象,只有一个type属性表示数据的MIME类型,默认是字符串
实例属性
属性名 描述
Blob.prototype.size 返回数据的大小
Blob.prototype.type 返回数据的MIME类型
实例方法
属性名 描述
Blob.prototype.slice([start,end,contentType]) 返回[start,end)[start,end)的子Blob对象,起始位置和结束位置默认是0和末尾,contentType是数据的MIME类型,默认为空字符串

FormData对象

通过脚本的形式填写表单,通过AJAX发送

构造方法
参数 描述
无参 表示空白表单
一个表单元素 会关联这个表单
实例方法
方法名 描述
FormData.get(key) 根据键名获取键值,若有多个同名键值对只会返回第一个
FormData.getAll(key) 根据键名获取键值对,返回是一个数组,包含所有同名键的键值
FormData.set(key,value) 设置键值对,若键名重复会覆盖,若第二个参数是文件,还可以使用第三个参数用来表示文件名
FormData.append(key,value) 添加一个键值对,若键名重复会生成两个相同键名的键值对,若第二个参数是文件,还可以使用第三个参数用来表示文件名
FormData.delete(key) 根据键名删除一个键值对
FormData.has(key) 判断是否具有该键名的键值对
FormData.keys() 返回一个迭代器对象,用于迭代所有的键名
FormData.values() 返回一个迭代器对象,用于迭代所有的键值
FormData.entries() 返回一个迭代器对象,用于迭代所有的键值对

FileList对象

FileList是一个存放File对象的集合,是一个伪数组,最常见的使用场合

  • 文件表单控件<input type="file" multiple>multiple表示可以多选,该控件的files属性就是用户上传的文件列表,即时没有设置multiple属性只能选择一个文件的情况下,也是一个包含一个元素的FileList集合
  • 拖拽事件中的DataTransfer.files属性,返回一个FileList实例

File对象

一个File对象代表一个文件,存放在FileList集合中

构造方法
参数 描述
第一个参数(必须) 数组,成员是二进制对象或字符串,表示文件内容
第二个参数(必须) 字符串,表示文件名或文件路径
配置对象(可选) type:MIME类型字符串,默认是空字符串;lastModified:时间戳表示最后修改时间,默认是现在
实例属性
属性名 描述
File.lastModified 文件最后修改时间
File.name 文件名
File.size 文件大小
File.type 文件类型

FileReader对象

对象用于读取File对象所包含的文件内容

构造方法

没有参数,只是生成实例

实例属性

状态与结果

属性名 描述
FileReader.error 读取文件时产生的错误对象
FileReader.readyState 返回一个整数,表示实例对象的状态;0=尚未加载任何数据,1=数据正在加载,2=加载完成
FileReader.result 读取完成后的文件内容,有可能是字符串,也可能是一个ArrayBuffer实例

监听函数

属性名 描述
FileReader.onprogress progress事件监听函数,读取时持续触发
FileReader.onabort abort事件监听函数,用户主动触发(即调用调用abort()方法),因为错误中止不会触发
FileReader.onerror error事件监听函数,因为错误导致中止时触发
FileReader.onload load事件监听函数,读取成功时触发
FileReader.onloadstart loadstart事件监听函数,开始读取时触发
FileReader.onloadend loadend事件监听函数,读取完成时触发,不管成功或失败
实例方法
方法名 描述
FileReader.abort(file) 终止读取操作,readyState属性将变成2
FileReader.readAsArrayBuffer(file) ArrayBuffer的格式读取文件,读取完成后result属性将返回一个 ArrayBuffer实例
FileReader.readAsBinaryString(file) 读取完成后,result属性将返回原始的二进制字符串
FileReader.readAsDataURL(file) 读取完成后,result属性将返回一个Base64 编码的字符串,代表文件内容;对于图片文件,这个字符串可以用于<img />元素的src属性上,由于这种便利性,这个字符串不能直接进行Base64解码,必须把前缀data:*/*;base64从字符串里删除以后,再进行解码
FileReader.readAsText(file[,encodeing]) 读取完成后,result属性将返回文件内容的文本字符串,第二个参数默认是utf-8

表单提交文件上传

<form method="post" enctype="multipart/form-data" action="#">
    <!-- 必须设置为post请求方式,而且enctype要设置为multipart/form-data表示混合表单数据 -->
    <input type="file" name="file" multiple />
    <!-- 文件表单控件,multiple表示可以多选 -->
  <input type="submit" name="submit" value="上传" />
  <!-- 提交按钮 -->
</form>

AJAX脚本文件上传

<input type="file" id="file" name="file" multiple />
<!-- 文件表单控件,multiple表示可以多选 -->
<input type="button" id="button" value="上传" />
<!-- 上传按钮 -->
<script>
    var button = document.getElementById("button"); //获取页面上传按钮
    button.addEventListener("click", function (e) { //为上传按钮绑定点击事件
        var file = document.getElementById("file"); //获取页面文件表单控件
        var files = file.files; //获取要上传的文件列表
        if (files.length > 0) { //若选择了文件
            var formData = new FormData();  //创建表单对象
            for (var i = 0; i < files.length; i++) {    //遍历要上传的文件列表
                formData.append("files", files[i], files[i].name);
              //放入文件表单对象中,不能使用set()方法因为会被覆盖掉
            }
            // console.log(formData.getAll("files"));   //可用此语句打印调试表单对象中是否有文件列表
        }
        var xhr = new XMLHttpRequest(); //创建XMLHttpRequest实例
        xhr.open('POST', '/up', true);  //设置请求行
        xhr.onload = function () {  //绑定上传成功时的回调
            if (xhr.status !== 200) {   //若响应状态码不是200
                console.err("上传失败");
            }
        };
        xhr.send(formData); //发送表单对象
    })
</script>

也可以直接发送文件,但是仅限一个文件

<input type="file" id="file" name="file" />
<!-- 文件表单控件,multiple表示可以多选 -->
<input type="button" id="button" value="上传" />
<!-- 上传按钮 -->
<script>
    var button = document.getElementById("button"); //获取页面上传按钮
    button.addEventListener("click", function (e) { //为上传按钮绑定点击事件
        var file = document.getElementById("file").files[0]; //获取页面文件表单控件
        // console.log(file); //可用此语句打印调试是否有文件
        if (file != null) { //若选中文件
            var xhr = new XMLHttpRequest(); //创建XMLHttpRequest实例
            xhr.open('POST', '/up', true); //设置请求行
            xhr.setRequestHeader('Content-Type', file.type);    //设置请求头中发送的文件类型为当前文件类型
            xhr.onload = function () { //绑定上传成功时的回调
                if (xhr.status !== 200) { //若响应状态码不是200
                    console.err("上传失败");
                }
            };
            xhr.send(file); //发送文件对象
        }

    })
</script>

同源限制

目的是为了保证用户信息的安全,网页A的设置的Cookie、LocalStorage和IndexedDB,网页B不能打开,发送的AJAX请求浏览器也拒绝响应,除非两个网页同源,同源是指:协议、域名和端口都相同

避免同源限制方法

客户端:设置两个页面的document.domain属性为同一个域名,浏览器是通过该属性来判断是否同源的

服务端:在设置Cookie时,使得Cookie的属性中domain值为相同或子域名可访问

iframe多窗口通信

在一个网页中嵌入另一个网页时(也适用于window.open()方法打开的窗口对象),每个网页都会有一个window对象,若两个窗口不是同源,就无法使用另一个窗口的DOM对象

同样可以使用document.domain属性设置为同一个域来避免同源限制

通信方案

基于hash通信:URL中的hash部分发生变化页面是不会刷新的,父子窗口都可以拿到彼此的window对象,然后在再修改location.hash就可以传递消息,父子窗口通过window,onhashchange来绑定hashchange事件的监听函数,监听函数中通过location.hash拿到传递的消息后,就可以做一系列操作

H5新增的方法:window.postMessage(message,URL),通过向指定URL的窗口(若设置为*,表示所有窗口)发送消息,无论这两个窗口是否同源,接收方若需要使用window.onmessage绑定message事件的监听函数,该监听函数的事件对象共有三个属性:source=发送消息的窗口对象、origin=发送的目标URL也就是发送方设置的URL、data发送的消息内容

AJAX的跨域请求

JSONP

使用script标签向服务器请求一个脚本,这不受跨域影响,所以可以为script标签的src参数填写URL时增加一个查询参数来指定返回结果时的回调函数,让服务器返回的脚本信息是调用该回调函数的脚本,限制就是只能是GET请求

示例
function addScriptTag(src) {	//动态的插入script标签,请求地址由外部传入
  var script = document.createElement("script");	//创建script标签
  script.setAttribute("type", "text/javascript");	//添加该属性表示是javascrip脚本
  script.src = src;	//添加src属性为要请求的地址
  document.body.appendChild(script);	//将该script插入到页面中
}
function fun(data){	//服务器一旦返回直接调用的该函数
  console.log(data.id);	//由于要求服务器返回的是JavaScript脚本,参数就是对象,所以可以直接以对象形式调用
}
window.onload = function () {	//当页面加载时
  addScriptTag("http://www.baidu.com/?callback=fun");	//调用jsonp跨域请求
  //服务器收到这个请求后需要返回以下形式脚本数据
  //fun({
  //  id:1,
  //  name:zhangsan
  //})
}

WebSocket

使用WebSocket进行协议进行通信,该协议不实行同源政策,只要服务器支持,就可以通过他进行跨域通信

CORS(跨域资源共享)

需要浏览器和服务器都支持,目前所有浏览器都支持,整个CORS通信过程,浏览器都是自动完成的,浏览器一旦发现AJAX请求跨域,就会自动附加一些头部信息,所以实现CORS通信的关机是服务器

简单请求

简单的说简单请求就是简单的请求方法和简单的请求头的结合,表单请求也是简单请求,表单请求在历史上是一直可以跨域请求的

  • 请求方法是:HEADGETPOST

  • 请求头只有:

    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:仅限三个值application/x-www-form-urlencodedmultipart/form-datatext/plain

简单请求流程

浏览器直接发出CORS请求,在请求头中添加一个Origin字段来标明本次请求来自哪个域(协议+域名+端口)

  • 若该域不在许可范围内,服务器会返回一个正常的HTTP响应,这个正常的响应中没有包含Access-Control-Allow-Origin字段,所以浏览器就会忽略掉接收请求,就会抛出一个错误被XMLHttpRequestonerror回调函数捕获,这种错误是无法使用状态码来判断的,因为是一个正常的HTTP响应
  • 若该域在许可范围内,服务器就会在响应头中添加以下三个字段
    • Access-Control-Allow-Origin:该字段是必须的,要么是*表示可接受任意域请求,要么与请求时的Origin的值相同(要注意域名和IP的映射关系浏览器是不知道的,所以也属于不同域,而且只能设置一个值,若想设置多个就需要在程序中实现)
    • Access-Control-Allow-Credentials:该字段可选,它的值是一个布尔值,表示是否允许浏览器发送Cookie,默认不发送(不设置就相当于false),只能设置为true;若只是将XMLHttpRequestwithCredentials设置为true,但是服务器不允许发送Cookie,则浏览器不会将响应内容返回给请求者,只有两者同时为true才行;设置上传Cookie后Access-Control-Allow-Origin字段就不能使用*,必须与请求网页同域,Cookie依然遵循同源政策,也就是上传是AJAX请求域的Cookie而不是当前页面的Cookie,当前页面也无法拿到AJAX请求域的Cookie
    • Access-Control-Expose-Headers:该字段可选,在CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个服务器返回的基本字段,若想使用该方法拿到其他的字段(包括自定义字段)就需要在该字段指定;6个基本字段包括:``Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma`
非简单请求

非简单请求的CORS请求,会在正式通信前增加一次HTTP查询请求,询问服务器当前页面域名是否在服务器允许跨域白名单中,以及可以使用哪些HTTP方法和请求头字段,只有得到肯定的答复,浏览器才会发出正式的AJAX请求,否则就会报错

比如:请求方法是PUTDELETEContent-Type字段的类型是application/json

1. 预检请求

  • 预检请求使用的是OPTIONS方法
  • 主要有这几个字段来进行询问
    • Origin:标明请求来自哪个域
    • Access-Control-Request-Method:要使用的请求方法
    • Access-Control-Request-Headers:要使用哪些自定义请求头字段,多个可使用逗号分隔

2. 预检请求响应

  • 主要有对应的字段来进行响应
    • Access-Control-Allow-Origin:允许跨域的域
    • Access-Control-Allow-Methods:允许使用的请求方法,多个用逗号分隔
    • Access-Control-Allow-Headers:允许使用的自定义请求头字段,多个用逗号分隔
    • Access-Control-Allow-Credentials:是否需要发送Cookie,与简单请求中的一致
    • Access-Control-Max-Age:指定多久之内不需要在发送预检请求,以秒为单位
  • 允许:上述的字段的值都应该大于等于(预检请求的值都包含在预检响应中)请求允许
  • 不允许:返回一个正常的HTTP响应,但是没有任何CORS相关字段或者明确表示请求不符合条件,这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获

3. 浏览器的正常请求和响应

一旦预检请求通过后,就都跟简单请求一样,请求头会增加一个Origin头信息字段,响应体会增加一个Access-Control-Allow-Origin字段

此作者没有提供个人介绍
最后更新于 2021-01-10