XHR&Fetch

来源:互联网 发布:玲珑加速器mac破解版 编辑:程序博客网 时间:2024/06/08 05:54

XMLHttpRequest

function createXHR(){    if (typeof XMLHttpRequest != "undefined"){        return new XMLHttpRequest();    } else if (typeof ActiveXObject != "undefined"){        if (typeof arguments.callee.activeXString != "string"){            var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",                            "MSXML2.XMLHttp"];            for (var i=0,len=versions.length; i < len; i++){                try {                    var xhr = new ActiveXObject(versions[i]);                    arguments.callee.activeXString = versions[i];                    break;                } catch (ex){                    //skip                }            }        }        return new ActiveXObject(arguments.callee.activeXString);    } else {        throw new Error("No XHR object available.");    }}var xmlhttp=createXHR();xmlhttp.onreadystatechange=function() //每当 readyState 属性改变时,就会调用该函数,用于异步请求,也可用onload,响应接收完毕会触发onload事件,无需检测readyState  {  //readyState表示请求过程的当前活动阶段 0: 请求未初始化,尚未open 1: 启动,open未send 2: 发送,已send,尚未接收到响应 3: 已接收部分响应数据 4: 请求已完成,且响应已就绪 status 200: "OK" 404: 未找到页面  if (xmlhttp.readyState==4)  { try {  //超时终止请求之后再访问status属性会报错        if((xmlhttp.status>=200&&xmlhttp.status<300)||(xmlhttp.status=304))//xmlhttp.status==304资源未更改,从缓存读            //responseText获得字符串形式的响应数据,responseXML获得XML形式的响应数据            document.getElementById("myDiv").innerHTML=xmlhttp.responseText;        else alert("Request was unsuccessful:"+xmlhttp.status);    }  }catch(ex){ }  }xmlhttp.open("get",url,true); //相对于当前页面的url,不能跨域,异步请求,该方法只是启动一个请求以备发送//xmlhttp.open("post",url,true);//var data=new FormData();  序列化表单//data.append("name","Lancy");//xmlhttp.send(data);xmlhttp.setRequestHeader("MyHeader","MyValue");xmlhttp.timeout=1000; //请求在1s内未返回自动终止,调用ontimeout事件处理程序xmlhttp.ontimeout=function(){    alert("time out!")}xmlhttp.send(null); //发送请求xmlhttp.abort() //接收到响应之前取消请求

收到响应后,数据会自动填充XHR对象的属性:
- responseText:作为响应主体被返回的文本
- status: 响应的HTTP状态

GET 还是 POST?
与 POST 相比,GET 更简单也更快,并且在大部分情况下都能用。GET请求可向url末尾添加参数,名值必须经过编码。在以下情况中,请使用 POST 请求:
- 无法使用缓存文件(更新服务器上的文件或数据库)
- 向服务器发送大量数据(POST 没有数据量限制)
- 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

为了避免得到缓存的结果,可以向 URL 添加一个唯一的 ID:
xmlhttp.open("GET","demo_get.asp?t=" + Math.random(),true);

如果需要像 HTML 表单那样 POST 数据,请使用 setRequestHeader()来添加 HTTP 头。然后在 send() 方法中规定您希望发送的数据:

xmlhttp.open("POST","ajax_test.asp",true);xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");xmlhttp.send("fname=Bill&lname=Gates");

XMLHttpRequest.setRequestHeader() 是设置HTTP请求头部的方法。此方法必须在 open() 方法和 send() 之间调用。设置的语法
XMLHttpRequest.setRequestHeader(bstrHeader, bstrValue);

参数

bstrHeader 字符串,名称。

bstrValue 字符串,值。

setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);

setRequestHeader(“Content-length”, paramsSend.length);

setRequestHeader(“Connection”, “close”);

通常在HTTP协议里,客户端像服务器取得某个网页的时候,必须发送一个HTTP协议的头文件告诉服务器客户端要下载什么信息以及相关的参数,如:

GET /bb.asp?www=1234 HTTP/1.1 Accept: */* Accept-Language: zh-cn UA-CPU: x86 Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) Host: www.e4j.cn:89 Connection: Keep-Alive Cookie: %C3%F7%CC%EC=%B0%CB;ASPSESSIONIDASDBSDRR=BLEDBIBBCGKBJAKJCFEJKGII

而 XMLHTTP 就是通过HTTP协议取得网站上的文件数据的,所以也要发送HTTP头给服务器。 但是 XMLHTTP 默认的情况下有些参数可能没有说明在HTTP头里,这是当我们需要修改或添加这些参数时就用到了setRequestHeader 方法。

就比如如果上面这段HTTP头文件内容是 XMLHTTP 提交默认的情况,当使用 setRequestHeader 方法后就这样,如:
XMLObject.setRequestHeader( “CONTENT-TYPE”, “application/x-www-form-urlencoded” )
setRequestHeader (“Connection”, “close”)
这时HTTP头信息就应该是这样了:

GET /bb.asp?www=1234 HTTP/1.1 Accept: */* Accept-Language: zh-cn UA-CPU: x86 Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) CONTENT-TYPE:application/x-www-form-urlencoded Host: www.e4j.cn:89 Connection: close Cookie: %C3%F7%CC%EC=%B0%CB;ASPSESSIONIDASDBSDRR=BLEDBIBBCGKBJAKJCFEJKGII

setRequestHeader方法只是XMLHTTP为添加或修改HTTP头提供的一个接口方法而已, 至于里面的值则是HTTP协议的含义,当然也可以放自己的东西进去,即使IIS不能识别你的信息也不会报错

如: setRequestHeader (“MyName”, “Supermanking”)

虽然IIS不会报错,但这个信息也可以有用,可以在ASP程序里读取HTTP头信息分析是否有 MyName: Supermanking 信息,可根据你的需求来做处理,还有,CONTENT-TYPE:application/x-www-form-urlencoded含义是表示客户端提交给服务器文本内容的编码方式是URL编码,即除了标准字符外,每字节以双字节16进制前加个“%”表示

当然还有其他编码方式,如:CONTENT-TYPE:multipart/form-data

至于:Content-length 就是表示提交的数据字节大小
http有几种提交方式,其中比较常用的就是 GET 和 POST

这个标志就放在HTTP头开头的地方,这样讲容易理解点
GET 方式是没有提交内容的,所以 Content-length 在 GET 模式下是无效的.
GET 传参数的方式就是通过虚拟地址传送,如:
GET /bb.asp?www=1234 HTTP/1.1
参数全部就只有 “www=1234” 这么多

如果用POST的话就有些不同,POST是将参数放到HTTP后面的,就以上面的HTTP作范例,用POST的方法传参数

POST /bb.asp HTTP/1.1 Accept: */* Accept-Language: zh-cn UA-CPU: x86 Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) CONTENT-TYPE:application/x-www-form-urlencoded Host: www.e4j.cn:89 Content-length: 8 Connection: close Cookie: %C3%F7%CC%EC=%B0%CB;ASPSESSIONIDASDBSDRR=BLEDBIBBCGKBJAKJCFEJKGII www=1234 

这时,数据就需要说明字节大小了

至于 Connection: Close,很明显英文的意思是 连接:关闭
只是客户端在提交数据时告诉服务器让谁先关闭连接而已。

在XMLHttpRequest发送请求之前加上以下头部可以避免缓存:

    XMLHttpRequest.setRequestHeader("If-Modified-Since","0");     XMLHttpRequest.send(null);

If-Modified-Since的头标签的作用
我们都知道浏览器是有缓存的,其实缓存里存储的不只是网页文件,还有服务器发过来的该文件的最后服务器修改时间。

If-Modified-Since是标准的HTTP请求头标签,在发送HTTP请求时,把浏览器端缓存页面的最后修改时间一起发到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行比较。

如果时间一致,那么返回HTTP状态码304(不返回文件内容),客户端接到之后,就直接把本地缓存文件显示到浏览器中。

如果时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。

解决缓存问题三个方法
1.时间戳方法 ——即在每次请求的url后面加上当前时间的字符串或其他类似的不会重复的随机字符串,这样浏览器每次发出的是不同的url,即会当做不同的请求来处理,而不会从缓存中读取。

    if(url.indexOf("?")>=0){//判断url中是否已经带有参数                    url = url + "&t=" + (new Date()).valueOf();                }else{                    url = url + "?t=" + (new Date()).valueOf();                }

2、在HTTP header上处理缓存

    <meta http-equiv="pragma" content="no-cache" />     <meta http-equiv="Cache-Control" content="no-cache,no-store, must-revalidate" />     <meta http-equiv="expires" content="Thu, 01 Jan 1970 00:00:01 GMT" />     <meta http-equiv="expires" content="0" />
  1. 在XMLHttpRequest发送请求之前加上:
    XMLHttpRequest.setRequestHeader("If-Modified-Since","0");     XMLHttpRequest.send(null);

Fetch

fetch 规范与 jQuery.ajax() 主要有两种方式的不同:
- 从 fetch()返回的 Promise 将不会拒绝HTTP错误状态, 即使响应是一个 HTTP 404 或 500。相反,它会正常解决 (其中ok状态设置为false), 并且仅在网络故障时或任何阻止请求完成时,它才会拒绝。
- 默认情况下, fetch在服务端不会发送或接收任何 cookies, 如果站点依赖于维护一个用户会话,则导致未经认证的请求(要发送 cookies,必须发送凭据头).

fetch(input[, init]);

input定义要获取的资源。这可能是:
- 一个 USVString 字符串,包含要获取资源的 URL。
- 一个 Request 对象。Request

var myRequest = new Request('flowers.jpg');var myURL = myRequest.url; // http://localhost:8000/flowers.jpgvar myMethod = myRequest.method; // GET

init 可选,一个配置项对象,包括所有对请求的设置。可选的参数有:
- method: 请求使用的方法,如 GET、POST。
- headers: 请求的头信息,形式为 Headers 的对象或包含 ByteString 值的对象字面量。
- body: 请求的 body 信息:可能是一个 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
- mode: 请求的模式,如 cors、 no-cors 或者 same-origin。
- credentials: 请求的 credentials,如 omit、same-origin 或者 include。为了在当前域名内自动发送 cookie , 必须提供这个选项, 从 Chrome 50 开始, 这个属性也可以接受 FederatedCredential 实例或是一个 PasswordCredential 实例。
- cache: 请求的 cache 模式: default 、 no-store 、 reload 、 no-cache 、 force-cache 或者 only-if-cached 。
- redirect: 可用的 redirect 模式: follow (自动重定向), error (如果产生重定向将自动终止并且抛出一个错误), 或者 manual (手动处理重定向). 在Chrome中,Chrome 47之前的默认值是 follow,从 Chrome 47开始是 manual。
- referrer: 一个 USVString 可以是 no-referrer、client或一个 URL。默认是 client。
- referrerPolicy: Specifies the value of the referer HTTP header. May be one of no-referrer、 no-referrer-when-downgrade、 origin、 origin-when-cross-origin、 unsafe-url 。
- integrity: 包括请求的 subresource integrity 值 ( 例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=)。

let myImage = document.querySelector('img');var myHeaders = new Headers();var myInit = { method: 'GET',               headers: myHeaders,               mode: 'cors',               cache: 'default' };fetch('flowers.jpg',myInit).then(function(response) {  return response.blob();}).then(function(myBlob) {    let objectURL = URL.createObjectURL(myBlob);    myImage.src = objectURL;});
var myHeaders = new Headers();var myInit = { method: 'GET',               headers: myHeaders,               mode: 'cors',               cache: 'default' };var myRequest = new Request('flowers.jpg', myInit);fetch(myRequest).then(function(response) {  return response.blob();}).then(function(myBlob) {  var objectURL = URL.createObjectURL(myBlob);  myImage.src = objectURL;});

Request() 和 fetch() 接受同样的参数。你甚至可以传入一个已存在的 request 对象来创造一个拷贝:

var anotherRequest = new Request(myRequest,myInit);

这里我们通过网络获取一个图像并将其插入到一个 元素中。最简单的用法是只提供一个参数用来指明想fetch到的资源路径,然后返回一个包含响应结果的promise(一个 Response 对象)。当然它只是一个 HTTP 响应,而不是真的图片。为了获取图片的内容,我们需要使用 blob() 方法(在Body mixin 中定义,被 Request 和 Response 对象实现, Fetch API 中的 Body mixin 代表 response/requestd的body属性,允许你声明其内容类型是什么以及应该如何处理,一个 Blob对象表示一个不可变的, 原始数据的类似文件对象。)。

Body 类定义了以下方法 (这些方法都被 Request 和Response所实现)以获取body内容. 这些方法都会返回一个被解析后的promise对象和数据.
- arrayBuffer()
- blob()
- json()
- text()
- formData()
比起XHR来,这些方法让非文本化的数据使用起来更加简单。

功能检测

Fetch API 的支持情况,可以通过检测 Headers、Request、Response 或 fetch() 是否在 Window 或 Worker 域中。比如你可以这样做:

if(self.fetch) {    // run my fetch request here} else {    // do something with XMLHttpRequest?}

检测请求是否成功

如果遇到网络故障,fetch() promise 将会 reject,带上一个 TypeError 对象。虽然这个情况经常是遇到了权限问题或类似问题——比如 404 不是一个网络故障。想要精确的判断 fetch() 是否成功,需要包含 promise resolved 的情况,此时再判断 Response.ok 是不是为 true。类似以下代码:

fetch('flowers.jpg').then(function(response) {  if(response.ok) {    response.blob().then(function(myBlob) {      var objectURL = URL.createObjectURL(myBlob);      myImage.src = objectURL;    });  } else {    console.log('Network response was not ok.');  }}).catch(function(error) {  console.log('There has been a problem with your fetch operation: ' + error.message);});

用 async/await 优化

try {  let response = await fetch(url);  let data = response.json();  console.log(data);} catch(e) {  console.log("Oops, error", e);}// 注:这段代码如果想运行,外面需要包一个 async function

参考链接
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch