如何发请求?
- 用form可以发post或get请求,但是但是会刷新页面或新开页面
- 用 a 可以发 get 请求,但是也会刷新页面或新开页面
- 用 img 可以发 get 请求,但是只能以图片的形式展示
- 用 link 可以发 get 请求,但是只能以 CSS、favicon 的形式展示
- 用 script 可以发 get 请求,但是只能以脚本的形式运行
所以急需一种API可以满足以下两个要求:
- get、post、put、delete 请求都行
- 想以什么形式展示就以什么形式展示
微软的突破
IE 5 率先在 JS 中引入 ActiveX 对象(API),使得 JS 可以直接发起 HTTP 请求。随后 Mozilla、 Safari、 Opera 也跟进了,取名 XMLHttpRequest,并被纳入 W3C 规范。 1.pngAJAX
- Jesse James Garrett 将如下技术取名叫做 AJAX(Async JavaScript And XML):异步的 JavaScript 和 XML
- 使用 XMLHttpRequest 发请求
- 服务器返回 XML 格式的字符串(现在都使用JSON来代替XML)
- JS 解析 XML,并更新局部页面
- AJAX就是用JS去发请求
- 响应的第四部分是字符串,可以用 JSON 语法表示一个对象,也可以用 JSON 语法表示一个数组,还可以用 XML 语法,还可以用 HTML 语法,还可以用 CSS 语法,还可以用 JS 语法,还可以用自创的语法
- 示例
myButton.addEventListener('click',(e)=>{
let request = new XMLHttpRequest()
request.open('get','/xxx')//配置request
request.send()
setInterval(()=>{console.log(request.readyState)},1)
})
结果:
2.png
XMLHttpRequest.readyState 属性返回一个 XMLHttpRequest 代理当前所处的状态
3.png
图2中没有出现0、2、3是因为他们运行太快,没有捕捉到;每一次都会按照0~4的状态来运行。
由此可见,每毫秒来捕捉也无法得到所有的状态,那么有没有一个属性只要状态发生变化就通知我?有的。
request.onreadystatechange
如何使用 XMLHttpRequest
myButton.addEventListener('click',(e)=>{
let request = new XMLHttpRequest()
request.open('get','/xxx')//配置request
request.send()
request.onreadystatechange = ()=>{
if(request.readyState === 4){
console.log('请求响应完毕了')
if(request.status >= 200 && request.status < 300){
console.log('说明请求成功')
console.log(request.responseText)
let string = request.responseText
let object = window.JSON.parse(string)
//把符合JSON语法的字符串转换成JS对应的值,JSON.parse是浏览器提供的
console.log(typeof object)
console.log(object)
}
}
}
})
//后端代码
else if(path==='/xxx'){
response.statusCode = 200
response.setHeader('Content-Type', 'text/json;charset=utf-8')
response.setHeader('Access-Control-Allow-Origin', 'http://frank.com:8001')
response.write(`
{
"note":{
"to": "小谷",
"from": "方方",
"heading": "打招呼",
"content": "hi"
}
}
`)
response.end()
}
原生JS写一个AJAX
let request = new XMLHttpRequest()//声明
request.open('get','/xxx')//配置request
request.send()//发送
request.onreadystatechange = ()=>{
if(request.readyState === 4){
if(request.status >= 200 && request.status < 300){
let string = request.responseText
let object = window.JSON.parse(string)//解析
}
}
}
JSON
- JSON是由Douglas Crockford(道格拉斯克罗克福德)构想设计的数据交换语言,它是一门新的语言,与JavaScript不一样
- JS VS JSON 4.png
同源策略
- 即只有 协议+端口+域名 一模一样才允许发 AJAX 请求,否则浏览器上的任何网页都可被随意盗取信息
- http://baidu.com 可以向 http://www.baidu.com 发 AJAX 请求吗? 不可以
-
http://baidu.com:80 可以向 http://baidu.com:81 发 AJAX 请求吗? 不可以
要保持一模一样才能发AJAX请求
- 如果想要请求别的域名,那么就给它的后台打电话,通过两种方式处理①JSONP(但它不能发POST请求);②CORS跨域;(用哪种方法都可以)
CORS跨域
- Cross-Origin Resource Sharing(跨站资源共享)
- 只需在需要共享的那个域名下加上一句代码
response.setHeader('Access-Control-Allow-Origin', 'http://frank.com:8001')
就是告诉浏览器http://frank.com:8001这个网站是我的朋友,你不要拦它,可以让它读我的内容
AJAX的所有功能
- 客户端的JS发起请求(浏览器上的)
- 服务端的JS发送响应(Node.js上的)
- JS 可以设置任意请求 header
第一部分 request.open('get', '/xxx') //浏览器默认get请求是不显示第四部分的
第二部分 request.setRequestHeader('Content-Type','x-www-form-urlencoded')
第四部分 request.send('a=1&b=2') //请求体 - JS 可以获取任意响应 header
第一部分 request.status //状态码
request.statusText //状态码的文字解释
第二部分 request.getResponseHeader('Content-Type') //获取指定的响应头
request.getAllResponseHeaders() //获取全部的响应头
第四部分 request.responseText //响应体
至此,HTTP是如何请求响应的,就大致了解了:
①客户端通过AJAX设置请求头,发送请求到服务器端(服务器端需要指定端口)
②服务器端设置响应并发送到客户端(客户端不需要指定端口)
用jQuery封装AJAX
window.jQuery = function(nodeOrSelector){
let nodes = {}
nodes.addClass = function(){}
return nodes
}
window.jQuery.ajax = function(url,method,body,success,fail){
let request = new XMLHttpRequest()
request.open(method,url)//配置request
request.onreadystatechange = ()=>{
if(request.readyState === 4){
if(request.status >= 200 && request.status < 300){
success.call(undefined,request.responseText)
}else if(request.status >= 400){
fail.call(undefined,request)
}
}
}
request.send(body)
}
window.$ = window.jQuery
myButton.addEventListener('click',(e)=>{
window.jQuery.ajax(
'/xxx',
'post',
'a=1&&b=2',
()=>{console.log(1)},
()=>{console.log(2)}
)
})
但是上面最大的不足就是ajax函数中参数太多,容易造成忘记每个参数代表什么,所以需要作出优化,把所有参数转换成一个对象传进去
window.jQuery.ajax = function(options){
let url = options.url
let method = options.method
let body = options.body
let success = options.success
let fail = options.fail
let headers = options.headers
......
}
利用ES6的解构赋值语法优化参数
window.jQuery.ajax = function(options){
let {url,method,body,success,fail,headers} = options
......
}
继续优化
window.jQuery.ajax = function({url,method,body,success,fail,headers}){
......
}
Promise
- 因为成功需要回调成功函数,失败要回调失败函数,但是每个库的成功失败回调函数名是不一样的,例如image.onload(成功),image.onerror(失败),我们不可能一一地去查每个库回调函数的名字,所以就引入promise(promise是window下的全局属性),利用promise的then属性。
then(()=>{},()=>{}) //成功执行第一个函数,失败执行第二个函数
- 利用jQuery的promise属性(不要忘记引入jQuery)
myButton.addEventListener('click',(e)=>{
$.ajax(
{url:'/xxx',
method:'post',
headers:{
'Content-Type':'x-www-form-urlencoded',
'doudou':'18'
}
}).then(
(text)=>{console.log(text)},
(request)=>{console.log(request)}
)
})
- 自己定义promise来封装AJAX
window.jQuery = function(nodeOrSelector){
let nodes = {}
nodes.addClass = function(){}
nodes.html = function(){}
return nodes
}
window.$ = window.jQuery
window.Promise = function(fn){
return {
then: function(){}
}
}
window.jQuery.ajax = function({url,method,body,headers}){
return new Promise(function(resolve, reject){ //这六个单词是最重要的
let request = new XMLHttpRequest()
request.open(method,url)//配置request
for(let key in headers){ //遍历对象中的属性
let value = headers[key]
request.setRequestHeader(key,value)
}
request.onreadystatechange = ()=>{
if(request.readyState === 4){
if(request.status >= 200 && request.status < 300){
resolve.call(undefined,request.responseText)
}else if(request.status >= 400){
reject.call(undefined,request)
}
}
}
request.send(body)
})
}
myButton.addEventListener('click',(e)=>{
let promise = window.jQuery.ajax(
{url:'/xxx',
method:'post',
headers:{
'Content-Type':'x-www-form-urlencoded',
'doudou':'18'
}
})
promise.then(
(text)=>{console.log(text)},
(request)=>{console.log(request)}
)
})
网友评论