题目
- 手写一个ajax
// GET请求
const xhr = new XMLHttpRwquest()
// true表示异步的网络请求,默认是true
xhr.open('GET','/api',true)
xhr.onreadStateChange = function(){
if(xhr.readState === 4){
if(xhr.status === 200){
console.log(JSON.parse(xhr.responseText))
}else{
console.log(其他情况'')
}
}
}
xhr.send(null)
// post请求
const xhr = new XMLHttpRwquest()
xhr.open('POST','/api',true)
xhr.onreadStateChange = function(){
if(xhr.readState === 4){
if(xhr.status === 200){
console.log(JSON.parse(xhr.responseText))
}else{
console.log(其他情况'')
}
}
}
const postData = {
userName:'xiaoming',
password:'xxx'
}
// JSON.stringify,将 JavaScript 值转换为 JSON 字符串
// 必须要转换成字符串发送,我们用其他工具,直接发送,是因为其他工具已经帮我们做了转换
xhr.send(JSON.stringify(postData))
// 结合promise
function ajax(url) {
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr < 300) || xhr === 304) {
resolve(JSON.parse(xhr.responseText))
} else if (xhr.status === 404) {
reject(new Error('404 not found'))
}
}
}
xhr.send(null)
})
return p
}
ajax('/data.json')
.then(res => {console.log(res})
.cathc(err => {console.error(err)})
- 跨域的常用实现方式
知识点
- XMLHttpRequest
- 状态码
`readyState`是XMLHttpRequest对象的一个属性,用来标识当前XMLHttpRequest对象处于什么状态。
// xhr.readState === 0 (未初始化),还未调用send方法
// xhr.readState === 1 (载入),已调用send方法,正在发送请求
// xhr.readState === 2 (载入完成),send方法执行完成,已经接受到全部响应内容
// xhr.readState === 3 (交互)正在解析响应内容
// xhr.readState === 4 (完成)响应内容解析完成,可以在客户端调用
`status`是XMLHttpRequest对象的一个属性,表示响应的HTTP状态码
// 在HTTP1.1协议下,HTTP状态码总共可分为5大类,如下表所示:
// 1xx 服务器收到请求,需要继续处理。例如101状态码,表示服务器将通知客户端使用更高版本的HTTP协议。
// 2XX 请求成功。例如200状态码,表示请求所希望的响应头或数据体将随此响应返回。
// 3XX 重定向。例如302状态码,表示临时重定向,请求将包含一个新的URL地址,客户端将对新的地址进行GET请求。
// 4XX 客户端错误。例如404状态码,表示客户端请求的资源不存在。
// 5XX 服务器错误。例如500状态码,表示服务器遇到了一个未曾预料的情况,导致了它无法完成响应,一般来说,这个问题会在程序代码出错时出现。
- 跨域:同源策略,跨域解决方案
什么是跨域?(同源策略)
- ajax请求时,浏览器要求当前网页和server必须同源
- 同源:协议,域名,端口号 三者一致,才叫同源
- 注意:加载图片,css,js可以无视同源策略
<img src="跨域的图片地址"/> // 可用于统计打点,可使用第三方统计服务
<link href="跨域的css地址"/> // 可使用CDN,CDN一般都是外域
<script src="跨域的JS地址"/> // 可使用CDN,CDN一般都是外域; 可实现JSONP
跨域的解决方式
注意:所有的跨域,都必须经过server端的允许和配合,未经server端的允许,就实现跨域,说明浏览器有漏洞,危险信号
- JSONP
JSONP跨域原理:
- script 可以绕过跨域
- 服务器可以任意动态拼接数据返回
- 所以,script就可以获得跨域的数据,只要服务端愿意返回
// 自己写JSONP
<body>
<p>jsonp跨域</p>
<script>
window.userInfo = function(data) {
console.log(data)
}
</script>
<script src="http://localhost:8002/jsonp.js?name=xxx&callabck=userInfo"></script>
</body>
// jsonp.js
userInfo(
{name:'xiaoming'}
)
// jQuery实现JSONP
$.ajax({
url: 'http:localhost:8002/demo.json',
dataType: 'jsonp', // 告诉jquery我们用jsonp
jsonpCallback: 'callback', //callback的名字
success: function (data) {
console.log(data)
}
})
- CORS(服务端支持)
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。
对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
ajax常用的插件
- jQuery中ajax的使用方式
$.ajax({
// 请求方式
type: 'POST',
// 请求的媒体类型
contentType: "application/json;charset=UTF-8",
// 请求地址
url: "http://127.0.0.1/admin/list/",
// 传送数据
data: JSON.stringify(list),
// 请求成功
success: function (result) {
console.log(result)
},
// 请求失败,包含具体的错误信息
error: function (e) {
console.log(e.status)
console.log(e.responseText)
}
})
- fetch
fetch是一种http数据请求方式,是XMLHttpRequest的一种替代方案。fetch不是ajax的进一步封装,而是原生JS,fetch函数就是原生JS,没有使用XMLHttpRequest对象。它默认返回 promise
fetch 不会从服务端发送和接收任何cookies,除非做了设置
// fetch的第一个参数是url,第二个参数可选,是一个配置,类似于jquery
fetch('http://example.com/movies.json')
.then(response => response.json())
.then(data => console.log(data));
// Example POST method implementation:
async function postData(url = '', data = {}) {
// Default options are marked with *
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
return response.json(); // parses JSON response into native JavaScript objects
}
postData('https://example.com/answer', { answer: 42 })
.then(data => {
console.log(data); // JSON data parsed by `data.json()` call
});
- axios
基于 Promise 的 HTTP 客户端,可以工作于浏览器中,也可以在 node.js 中使用
功能:
- 从浏览器中创建
XMLHttpRequest
- 从nodejs中创建 http请求
- 支持promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持方式XFRS攻击
// GET请求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response)
})
.catch(function(error){
console.log(error)
})
axios.get('/user', {
params: {
ID:12345
}
})
.then(function (response) {
console.log(response)
})
.catch(function(error){
console.log(error)
})
// POST请求
axios.post('/user', {
firstName: 'li',
lastName:'xiaoming'
})
.then(function (response) {
console.log(response)
})
.catch(function(error){
console.log(error)
})
// 执行多个并发请求
function getUserAccount() {
return axios.get('/user/12345')
}
function getUserPermissions() {
return axios.get('/user/12345/permissions')
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
console.log("所有请求完成")
console.log("请求结果1",acct)
console.log("请求结果2",perms)
}))
网友评论