XHR&Fetch

本文详细介绍了XMLHttpRequest和Fetch API的使用方法,包括创建请求、发送数据、处理响应及避免缓存等内容。同时对比了GET与POST的区别,以及Fetch API相较于XMLHttpRequest的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.jpg
var 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值