一、XMLHttpRequest API
XMLHttpRequest详解
XMLHttpRequest 是一个浏览器接口,使得 Javascript 可以进行 HTTP (S) 通信。最早,微软在 IE 5 引进了这个接口。因为它太有用,其他浏览器也模仿部署了,ajax 操作因此得以诞生。但是,这个接口一直没有标准化,每家浏览器的实现或多或少有点不同。HTML 5 的概念形成后,W3C 开始考虑标准化这个接口。2008年 2 月,就提出了 XMLHttpRequest Level 2 草案。这个 XMLHttpRequest 的新版本,提出了很多有用的新功能,将大大推动互联网革新。
XMLHttpRequest对象是ajax的基础,XMLHttpRequest 用于在后台与服务器交换数据。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
目前所有浏览器都支持XMLHttpRequest新版本的 XMLHttpRequest 对象,针对老版本的缺点,做出了大幅改进。
- 可以设置 HTTP 请求的时限。
- 可以使用 FormData 对象管理表单数据。
- 可以上传文件。* 可以请求不同域名下的数据(跨域请求)。
- 可以获取服务器端的二进制数据。
- 可以获得数据传输的进度信息。
五步使用法:
1.创建XMLHTTPRequest对象
2.使用open方法设置和服务器的交互信息
3.设置发送的数据,开始和服务器端交互
4.注册事件
5.更新界面
GET请求:
//步骤一:创建异步对象
var ajax = new XMLHttpRequest();
//步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数,动态的传递参数starName到服务端
ajax.open('get','getStar.php?starName='+name);
//步骤三:发送请求
ajax.send();
//步骤四:注册事件 onreadystatechange 状态改变就会调用
ajax.onreadystatechange = function () {
if (ajax.readyState==4 &&ajax.status==200) {
//步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
console.log(ajax.responseText);//输入相应的内容
}
}
POST请求:
//创建异步对象
var xhr = new XMLHttpRequest();
//设置请求的类型及url
//post请求一定要添加请求头才行不然会报错
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.open('post', '02.post.php' );
//发送请求
xhr.send('name=fox&age=18');
xhr.onreadystatechange = function () {
// 这步为判断服务器是否正确响应
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
};
封装XMLHttpRequest方法
function ajax_method(url,data,method,success) {
// 异步对象
var ajax = new XMLHttpRequest();
// get 跟post 需要分别写不同的代码
if (method=='get') {
// get请求
if (data) {
// 如果有值
url+='?';
url+=data;
}else{
}
// 设置 方法 以及 url
ajax.open(method,url);
// send即可
ajax.send();
}else{
// post请求
// post请求 url 是不需要改变
ajax.open(method,url);
// 需要设置请求报文
ajax.setRequestHeader("Content-type","application/x-www-form-urlencoded");
// 判断data send发送数据
if (data) {
// 如果有值 从send发送
ajax.send(data);
}else{
// 木有值 直接发送即可
ajax.send();
}
}
// 注册事件
ajax.onreadystatechange = function () {
// 在事件中 获取数据 并修改界面显示
if (ajax.readyState==4&&ajax.status==200) {
// console.log(ajax.responseText);
// 将 数据 让 外面可以使用
// return ajax.responseText;
// 当 onreadystatechange 调用时 说明 数据回来了
// ajax.responseText;
// 如果说 外面可以传入一个 function 作为参数 success
success(ajax.responseText);
}
}
}
二、Ajax
Ajax介绍
ajax的出现,刚好解决了传统方法的缺陷。
AJAX 是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。AJAX 即 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。它可以在不重新加载整个页面的情况下完成与服务器交换数据并更新部分网页。
AJAX 是一种用于创建快速动态网页的技术。
通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。所有现代浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject)。
传统方法的缺点:
传统的web交互是用户触发一个http请求服务器,然后服务器收到之后,在做出响应到用户,并且返回一个新的页面,每当服务器处理客户端提交的请求时,客户都只能空闲等待,并且哪怕只是一次很小的交互、只需从服务器端得到很简单的一个数据,都要返回一个完整的HTML页,而用户每次都要浪费时间和带宽去重新读取整个页面。这个做法浪费了许多带宽,由于每次应用的交互都需要向服务器发送请求,应用的响应时间就依赖于服务器的响应时间。这导致了用户界面的响应比本地应用慢得多。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3S0UUCs0-1609421673666)(en-resource://database/4501:1)]
一个完整的AJAX请求包括五个步骤:
1.创建XMLHTTPRequest对象
2.使用open方法创建http请求,并设置请求地址
3.设置发送的数据,开始和服务器端交互
4.注册事件
5.获取响应并更新界面这里列出get请求和post请求的例子:
GET请求:
//请求函数
function f1(){
console.log('start');
//1.创建AJAX对象
var ajax = new XMLHttpRequest();
//4.给AJAX设置事件(这里最多感知4[1-4]个状态)
ajax.onreadystatechange = function(){
//5.获取响应
//responseText 以字符串的形式接收服务器返回的信息
//console.log(ajax.readyState);
if(ajax.readyState == 4 && ajax.status == 200){
var msg = ajax.responseText;
console.log(msg);
//alert(msg);
var divtag = document.getElementById('result');
divtag.innerHTML = msg;
}
}
//2.创建http请求,并设置请求地址
var username = document.getElementsByTagName('input')[0].value;
var email = document.getElementsByTagName('input')[1].value;
username = encodeURIComponent(username); //对输入的特殊符号(&,=等)进行编码
email = encodeURIComponent(email);
ajax.open('get','response.php?username='+username+'&email='+email);
//3.发送请求(get--null post--数据)
ajax.send(null);
}
POST请求:
//请求函数
function f1(){
//console.log('start');
//1.创建AJAX对象
var ajax = new XMLHttpRequest();
//4.给AJAX设置事件(这里最多感知4[1-4]个状态)
ajax.onreadystatechange = function(){
//5.获取响应
//responseText 以字符串的形式接收服务器返回的信息
//console.log(ajax.readyState);
if(ajax.readyState == 4 && ajax.status == 200){
var msg = ajax.responseText;
console.log(msg);
//alert(msg);
var divtag = document.getElementById('result');
divtag.innerHTML = msg;
}
}
//2.创建http请求,并设置请求地址
ajax.open('post','response.php');
//post方式传递数据是模仿form表单传递给服务器的,要设置header头协议
ajax.setRequestHeader("content-type","application/x-www-form-urlencoded");
//3.发送请求(get--null post--数据)
var username = document.getElementsByTagName('input')[0].value;
var email = document.getElementsByTagName('input')[1].value;
username = encodeURIComponent(username); //对输入的特殊符号(&,=等)进行编码
email = encodeURIComponent(email);
var info = 'username='+username+'&email='+email; //将请求信息组成请求字符串
ajax.send(info);
}
三、Fetch API请求:
Fetch介绍
Fetch 是浏览器提供的原生 AJAX 接口。由于原来的XMLHttpRequest不符合关注分离原则,且基于事件的模型在处理异步上已经没有现代的Promise等那么有优势。因此Fetch出现来解决这种问题。Fetch API 提供了能够用于操作一部分 HTTP 的 JavaScript 接口,比如 requests 和 responses。它同时也提供了一个全局的 fetch() 方法——能够简单的异步的获取资源。
使用 window.fetch 函数可以代替以前的 . a j a x 、 . ajax、 .ajax、.get 和 $.post。
Fetch 提供了对 Request
和 Response
(以及其他与网络请求有关的)对象的通用定义。使之今后可以被使用到更多地应用场景中:无论是 service worker、Cache API、又或者是其他处理请求和响应的方式,甚至是任何一种需要你自己在程序中生成响应的方式。
它同时还为有关联性的概念,例如CORS和HTTP原生头信息,提供一种新的定义,取代它们原来那种分离的定义。发送请求或者获取资源,需要使用WindowOrWorkerGlobalScope.fetch()
方法。它在很多接口中都被实现了,更具体地说,是在 Window 和WorkerGlobalScope
接口上。因此在几乎所有环境中都可以用这个方法获取到资源。
fetch() 必须接受一个参数——资源的路径。无论请求成功与否,它都返回一个 Promise 对象,resolve 对应请求的 Response。你也可以传一个可选的第二个参数 init(参见 Request)。
一旦 Response 被返回,就可以使用一些方法来定义内容的形式,以及应当如何处理内容(参见 Body)。你也可以通过Request()
和 Response()
的构造函数直接创建请求和响应,但是我们不建议这么做。他们应该被用于创建其他 API 的结果(比如,service workers
中的 FetchEvent.respondWith
)。
Fetch接口
Fetch 提供了对 Request 和 Response 等对象通用的定义。
发送请求或者获取资源,需要使用 fetch() 方法。
处理 JSON响应
假设需要请求 JSON —— 回调结果对象 response 中有一个json()方法,用来将原始数据转换成 JavaScript 对象:
fetch('https://davidwalsh.name/demo/arsenal.json').then(function(response) {
// 转换为 JSON
return response.json();
}).then(function(j) {
// 现在, `j` 是一个 JavaScript object
console.log(j);
});
这很简单 , 只是封装了 JSON.parse(jsonString) 而已, 但 json 方法还是很方便的。
处理基本的Text / HTML响应
SON 并不总是理想的请求/响应数据格式, 那么我们看看如何处理 HTML或文本结果:
fetch('/next/page')
.then(function(response) {
return response.text();
}).then(function(text) {
// <!DOCTYPE ....
console.log(text);
});
如上面的代码所示, 可以在 Promise 链式的 then 方法中, 先返回 text() 结果 ,再获取 text
fetch("users.json").then(function(res) {
console.log(res.headers.get('Content-Type'));
console.log(res.headers.get('Data'));
console.log(res.status);
console.log(res.statusText);
console.log(res.type);
console.log(res.url);
})
响应类型当我们发送fetch请求时,返回的res.type可能是basic、cors或opaque中的一种。这些类型可以告知我们资源从何而来,这样就能知道该如何处理响应对象。当我们请求的是同一域下的资源时,响应返回的类型为basic,此时没有任何限制,我们可以查看响应中的任何数据。如何请求的是跨域资源,那么会返回一个CORS类型的头部,并且响应类型为cors。这种类型跟上面的basic非常相似,只是它对响应头部的字段访问有限制,你只可以访问这些属性:
. Cache-Control
. Content-Language
. Content-Type
. Expires
. Last-Modified
. Pragma
我们可以为fetch请求定义mode属性,来保证只有符合条件的请求才会被处理。可以设置的mode属性值如下:same-origin 只有请求相同域下的资源才能成功,其他请求均被拒绝。
cors 允许请求同域或者跨域资源,但是跨域必须返回相应的跨域请求头部。
cors-with-forced-preflight 在发出实际请求前先做preflight检查。
no-cors 针对跨域资源做请求,但是不返回CORS的响应头,这是属于opaque类型的响应(window下无法使用)
在使用mode时,需要将fetch请求的第二个参数作为配置对象,并在其中配置具体的模式,如下代码:
fetch("http://some-site.com/cors-enabled/some.json",{mode: 'cors'})
.then(function(res){
return res.text();
})
.then(function(text) {
console.log('Request successfully', text);
})
.catch(function(err) {
console.log('Request failed', error)
})
Promise 方法链
Promise 的特性之一就是可以实现链式调用,fetch也可以使用该特性,同时,使用链式调用可以让请求的处理逻辑更加通用。
如果使用接口反馈的JSON格式数据,那么针对每次响应,我们都需要检查响应状态并做JSON格式转换。其实还能简化代码,那就是把状态监测和JSON转换的代码放到单独的函数中去。比如:
function status(res) {
if (res.status >= 200 && res.status < 300) {
return Promise.resolve(response)
} else {
return Promise.reject(new Error(res.statusText))
}
}
function json(res) {
return res.json()
}
fetch('user.json')
.then(status)
.then(json)
.then(function(data) {
console.log('Request succeeded with JSON response', data);
})
.catch(function(err) {
console.log('Request failed', error);
})
Response相关属性及方法
bodyUsed标记返回值是否被使用过
这样设计的目的是为了之后兼容基于流的API,让应用一次消费data,这样就允许了JavaScript处理大文件例如视频,并且可以支持实时压缩和编辑。
fetch('/test/content.json').then(function(res){
console.log(res.bodyUsed); // false
var data = res.json();
console.log(res.bodyUsed); //true
return data;
}).then(function(data){
console.log(data);
}).catch(function(error){
console.log(error);
});
headers
返回Headers对象,该对象实现了Iterator,可通过for…of遍历
fetch('/test/content.json').then(function(res){
var headers = res.headers;
console.log(headers.get('Content-Type')); // application/json
console.log(headers.has('Content-Type')); // true
console.log(headers.getAll('Content-Type')); // ["application/json"]
for(let key of headers.keys()){
console.log(key); // datelast-modified server accept-ranges etag content-length content-type
}
for(let value of headers.values()){
console.log(value);
}
headers.forEach(function(value, key, arr){
console.log(value); // 对应values()的返回值
console.log(key); // 对应keys()的返回值
});
return res.json();
}).then(function(data){
console.log(data);
}).catch(function(error){
console.log(error);
});
ok是否正常返回
代表状态码在200-299之间
status状态码( 200表示 成功)statusText状态描述 (‘OK’表示 成功)typebasic:正常的,同域的请求,包含所有的headers。排除Set-Cookie和Set-Cookie2。
cors:Response从一个合法的跨域请求获得,一部分header和body可读。
error:网络错误。Response的status是0,Headers是空的并且不可写。当Response是从Response.error()中得到时,就是这种类型。
opaque: Response从”no-cors”请求了跨域资源。依靠Server端来做限制。url返回完整的url字符串。如:’http://xxx.com/xx?a=1’arrayBuffer()返回ArrayBuffer类型的数据的Promise对象blob()返回Blob类型的数据的Promise对象clone()生成一个Response的克隆
body只能被读取一次,但clone方法就可以得到body的一个备份
克隆体仍然具有bodyUsed属性,如果被使用过一次,依然会失效
fetch('/test/content.json').then(function(data){
var d = data.clone();
d.text().then(function(text){
console.log(JSON.parse(text));
});
return data.json();
}).then(function(data){
console.log(data);
}).catch(function(error){
console.log(error);
});
- json():返回JSON类型的数据的
- Promise:对象text()返回Text类型的数据的Promise对象
- ormData()返回FormData类型的数据的Promise对象
GET请求
fetch('/test/content.json').then(function(data){
return data.json();
}).then(function(data){
console.log(data);
}).catch(function(error){
console.log(error);
});
POST请求
fetch('/test/content.json', { // url: fetch事实标准中可以通过Request相关api进行设置
method: 'POST',
mode: 'same-origin', // same-origin|no-cors(默认)|cors
credentials: 'include', // omit(默认,不带cookie)|same-origin(同源带cookie)|include(总是带cookie)
headers: { // headers: fetch事实标准中可以通过Header相关api进行设置
'Content-Type': 'application/x-www-form-urlencoded' // default: 'application/json'
},
body: 'a=1&b=2' // body: fetch事实标准中可以通过Body相关api进行设置
}).then(function(res){ res: fetch事实标准中可以通过Response相关api进行设置
return res.json();
}).then(function(data){
console.log(data);
}).catch(function(error){
});
处理Blob结果
通过 fetch 加载图像或者其他二进制数据, 则会略有不同:
fetch('flowers.jpg')
.then(function(response) {
return response.blob();
})
.then(function(imageBlob) {
document.querySelector('img').src = URL.createObjectURL(imageBlob);
});
响应 Body mixin 的 blob() 方法处理响应流(Response stream), 并且将其读完
提交表单数据(Posting Form Data)
另一种常用的 AJAX 调用是提交表单数据 —— 示例代码如下:
fetch('/submit', {
method: 'post',
body: new FormData(document.getElementById('comment-form'))
});
提交 JSON 的示例如下:
fetch('/submit-json', {
method: 'post',
body: JSON.stringify({
email: document.getElementById('email').value
answer: document.getElementById('answer').value
})
});
缺点
使用 fetch 无法取消一个请求。这是因为 Fetch API 基于 Promise,而 Promise 无法做到这一点。由于 Fetch 是典型的异步场景,所以大部分遇到的问题不是 Fetch 的,其实是 Promise 的。