ajax
题目
- 手写一个简易的 ajax
- 跨域的常用实现方式
手写一个简易的 ajax
Ajax一般是通过XMLHttpRequest对象来是实现的
let request =new XMLHttpRequest() //声明一个XMLHttpRequest对象
常用的方法和属性
XMLHttpRequest对象的setRequestHeader方法
语法:request.setRequestHeader(key,value) //设置请求头
XMLHttpRequest对象的open方法
语法:request.open(method, url, async, user, password); //初始化请求;一般使用前三个参数,后三个为可选参数
method参数
要使用的HTTP方法,比如「GET」、「POST」、「PUT」、「DELETE」、等。对于非HTTP(S) URL被忽略。
url参数
表示向其发送请求的URL。
async 可选参数
表示需不需要异步执行操作,不传入则该参数默认为true,已完成事务的通知可供事件监听器使用。如果值为false,send()方法直到收到答复前不会返回。
XMLHttpRequest对象的send方法
语法:request.send(data) //发送请求,data参数为可选参数。如果是异步请求,则此方法会在请求发送后立即返回;如果是同步请求,则此方法直到响应到达后才会返回。
data参数
表示发送请求时的请求体
在通过send方法发送请求后,request对象在收到响应数据时会自动填充到其对应的属性中,xhr 具有以下常用属性:
responText:响应返回的数据内容
responseXML: 如果响应内容是"text/xml"“application/xml”,这个属性将保存响应数据的 XML DOM文档
status: 相应的HTTP状态码(200,302,404,503等)
statusText: HTTP状态说明内容(如status的值为200,则statusText的值为"ok")
readyState: 无论请求是否成功,都回响应的一个属性,表示当前的状态
总共有5个状态值,分别为0~4,每个值代表了不同的含义
0:初始化,XMLHttpRequest对象还没有完成初始化
1:载入,XMLHttpRequest对象开始发送请求
2:载入完成,XMLHttpRequest对象的请求发送完成
3:解析,XMLHttpRequest对象开始读取服务器的响应
4:完成,XMLHttpRequest对象读取服务器响应结束
timeout: 设置请求超时时间
需要结合ontimeout事件使用
发送一个请求,readyState会一直改变状态值,当值改变时会触发onreadystatechange事件,所以可以在此处做请求成功/失败后的数据操作,得出以下代码
request.onreadystatechange=()=>{
if(request.readyState === 4){ //响应已结束时
if (request.status === 200 && request.status < 300 || request.status === 304) {//2xx的状态码均表示成功,304状态码表示请求与上次一致
let tempRT = request.responseText //将响应的数据内容赋值给tempRT变量
console.log(tempRT) //打印数据内容
}else if(request.status > 400){ //大于400的状态码均表示为请求失败
console.log("request fail") //打印请求失败
}
}
}
最后封装这个手写的ajax
window.myAjax = {
ajax: (options) => { //接受一个对象参数
let method = options.method
let url = options.url
let header = options.header
let body = options.body
let request = new XMLHttpRequest()
request.open(method, url)
for (key in header) {
let temp = key
request.setRequestHeader(key, temp)
}
request.onreadystatechange = () => {
if (request.readyState === 4) {
if (request.status === 200) {
let temp = request.responseText
console.log(temp)
}
}
}
request.send(body)
}
}
options = {} //设置传参
myAjax.ajax(options) //引入该文件,调用全局变量myAjax的ajax方法
功能较为简易,以实现基础功能为需求
跨域的常用实现方式
什么是跨域?
同源策略是由 Netscape 提出的著名安全策略,是浏览器最核心、基本的安全功能,它限制了一个源(origin)中加载文本或者脚本与来自其他源(origin)中资源的交互方式
,所谓的同源就是指协议、域名、端口相同。
当浏览器执行一个脚本时会检查是否同源,只有同源的脚本才会执行,如果不同源即为跨域
跨域的几种方式
在实际项目中,经常会遇到在一个域名下请求另外一个域名的资源的情况,这就会涉及到跨域问题,下面我们来探讨下跨域的几种实现方式(下面所有例子中,后端使用 node.js,框架 express):
1、jsonp
最常见的一种跨域方式,其背后原理就是利用了 script 标签不受同源策略的限制,在页面中动态插入了 script,script 标签的 src 属性就是后端 api 接口的地址,并且以 get 的方式将前端回调处理函数名称告诉后端,后端在响应请求时会将回调返还,并且将数据以参数的形式传递回去。
前端:
// http://127.0.0.1:8888/jsonp.html
var script = document.createElement('script');
script.src = 'http://127.0.0.1:2333/jsonpHandler?callback=_callback';
document.body.appendChild(script); //插入script标签
// 回调处理函数 _callback
var _callback = function(obj) {
for(key in obj) {
console.log('key: ' + key +' value: ' + obj[key]);
}
}
后端:
// http://127.0.0.1:2333/jsonpHandler
app.get('/jsonpHandler', (req, res) => {
let callback = req.query.callback;
let obj = {
type: 'jsonp',
name: 'weapon-x'
};
res.writeHead(200, {"Content-Type": "text/javascript"});
res.end(callback + '(' + JSON.stringify(obj) + ')');
})
在 jsonp.html 中打开控制台可以看到返回数据的输出:
2、CORS
Cross-Origin Resource Sharing(跨域资源共享)是一种允许当前域(origin)的资源(比如html/js/web service)被其他域(origin)的脚本请求访问的机制。
当使用 XMLHttpRequest 发送请求时,浏览器如果发现违反了同源策略就会自动加上一个请求头 origin,后端在接受到请求后确定响应后会在 Response Headers 中加入一个属性 Access-Control-Allow-Origin,值就是发起请求的源地址(http://127.0.0.1:8888),浏览器得到响应会进行判断 Access-Control-Allow-Origin 的值是否和当前的地址相同,只有匹配成功后才进行响应处理。
现代浏览器中和移动端都支持 CORS(除了opera mini),IE 下需要8+
前端:
// http://127.0.0.1:8888/cors.html
var xhr = new XMLHttpRequest();
xhr.onload = function(data) {
var _data = JSON.parse(data.target.responseText)
for(key in _data) {
console.log('key: ' + key + ' value: ' + _data[key]);
}
};
xhr.open('POST','http://127.0.0.1:2333/cors',true);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send();
后端:
// http://127.0.0.1:2333/cors
app.post('/cors', (req, res) => {
if(req.headers.origin) {
res.writeHead(200, {
"Content-Type": "text/html; charset=UTF-8",
"Access-Control-Allow-Origin": 'http://127.0.0.1:8888'
});
let people = {
type: 'cors',
name: 'weapon-x'
}
res.end(JSON.stringify(people));
}
})
可以在开发者工具里面看到请求的详细信息,并且在控制台也可以看到返回的数据输出
3、服务器跨域
在前后端分离的项目中可以借助服务器实现跨域,具体做法是:前端向本地服务器发送请求,本地服务器代替前端再向真实服务器接口发送请求进行服务器间通信,本地服务器其实充当个「中转站」的角色,再将响应的数据返回给前端,来看下实际例子:
前端:
// http://127.0.0.1:8888/server
var xhr = new XMLHttpRequest();
xhr.onload = function(data) {
var _data = JSON.parse(data.target.responseText)
for(key in _data) {
console.log('key: ' + key +' value: ' + _data[key]);
}
};
xhr.open('POST','http://127.0.0.1:8888/feXhr',true); // 向本地服务器发送请求
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send("url=http://127.0.0.1:2333/beXhr"); // 以参数形式告知需要请求的后端接口
后端:
// http://127.0.0.1:8888/feXhr
app.post('/feXhr', (req, res) => {
let url = req.body.url;
superagent.get(url) //使用 superagent 向实际接口发起请求
.end((err, docs) => {
if(err) {
console.log(err);
return
}
res.end(docs.res.text); // 返回给前端
})
})
// http://127.0.0.1:2333/beXhr
app.get('/beXhr', (req, res) => {
let obj = {
type: 'superagent',
name: 'weapon-x'
};
res.writeHead(200, {"Content-Type": "text/javascript"});
res.end(JSON.stringify(obj)); //响应
})
回到 http://127.0.0.1:8888/server 页面打开控制台可以看到数据输出
4、postmessage跨域
在 HTML5 中新增了 postMessage 方法,postMessage 可以实现跨文档消息传输 Cross Document Messaging,IE8,Firefox 3,Opera 9,Chrome 3 和 Safari 4 都支持 postMessage。
该方法可以通过绑定 window 的 message 事件来监听发送跨文档消息传输内容。
使用 postMessage 实现跨域的话原理就类似于 jsonp,动态插入 iframe标签,再从 iframe 里面拿回数据
,私认为用作跨页面通信更加适合
总结
当然还有其他实现跨域的方式比如在ie8、9下 XDR 跨域方案,flash 方案,以上是一些常用的跨域方案,都各有利弊,比如:jsonp 只能发送 get 请求、服务器跨域需要另起服务器等等,大家可以根据自己项目需求选择适合的解决方案,如果对于跨域还有其他看法或者文中出现错误,欢迎大家留言 😄
知识点
- XMLHttpRequest
- 状态码
- 跨域:同源策略,(如何绕过), JSONP CORS 跨域解决方案
XMLHttpRequest
xhr.readyState
- 0 - (未初始化)还没有调用 send()方法
- 1 - (载入)已调用 send()方法,正在发送请求
- 2 - (载入完成)send()方法执行完成,已经接受到全部响应内容
- 3 - (交互)正在解析响应内容
xhr.status
- 2xx - 表示成功处理请求。如 200
- 3xx - 需要重定向,浏览器直接跳转,如 301,302,304
- 4xx - 客户端请求错误,如 404,403
- 5xx - 服务器端错误
跨域
- 什么是跨域(同源策略)
- JSONP
- CORS(服务端支持)
- 所有的跨域,都必须经过 server 端允许和配合
- 未经 server 端允许就实现跨域,说明浏览器有漏洞,危险信号
同源策略
- ajax 请求时,浏览器要求当前网页和 server 必须同源(安全)
- 同源:协议,域名,端口,三者必须一致
- 前端:http://:8080/ ;server:https:///api/xxx
加载图片 css js 可无视同源策略
- < img src = 跨域的图片地址 />
- <l ink href =跨域的 css 地址 />
- < script src = 跨域的 js 地址 >< /script >
- < img / > 可用于统计打点,可食用第三方统计服务
- < link / > < script > 可食用 CDN , CDN 一般都是外域
- < script > 可实现 JSONP
JSONP
- 访问 http://imooc.com/ , 服务端一定返回一个 html 文件吗?
- 服务器可以任意动态拼接数据返回,只要符合 html 格式要求
- 同理于 < script src = “https://imooc.com/getData.js”>
- < scrip > 可绕过跨域限制
- 服务器可以任意动态拼接数据返回
- 所以 , < scrip > 就可以获得跨域的数据,只要服务端愿意返回