JSONP发展
了解了JSONP技术栈后,知道了JSONP是AJAX出现之前后端交互最好的解决方案,但它依然没解决问题,用JSONP只能发送GET请求,不能发其他请求
form表单可以发GET请求,也可以发POST请求,POST请求没有请求参数,但是会刷新页面或新开页面
a标签可以发GET请求,会刷新页面或新开页面
img标签可以发GET请求,只能以图片方式展示
let image = document.createElement('img')
img.src = '/xxx'
imgae.onload = () => {}
imgae.onerror = () => {}
link可以发GET请求,但是只能以CSS、favicon的形式展示
let link = document.createElement('link')
link.src = '/xxx'
document.head.appendChild(link)
link.onload = () => {}
link.onerror = () => {}
用script可以发GET请求,但是只能以脚本的形式运行
let script = document.createElement('script')
script.src = '/xxx'
document.body.appendChild(script)
script.onload = () => {}
script.onerror = () => {}
有没有什么方式可以实现
- get、post、put、delete请求都行
- 想以什么形式展示就以什么形式展示
微软的突破
IE 5 率先在 JS 中引入 ActiveX 对象(API),使得 JS 可以直接发起 HTTP 请求。
随后 Mozilla、 Safari、 Opera 也跟进(抄袭)了,取名 XMLHttpRequest,并被纳入 W3C 规范
AJAX
AJAX 全称 Async Javascript and XML 翻译成中文:异步的 JavaScript 和 XML
Ajax 技术的核心是 XMLHttpRequest 对象(简称:XHR),可以在不刷新页面页面也能取得新的数据。
满足下面的条件就是AJAX
- 使用 XMLHttpReques 发请求
- 服务器返回 XML 格式的字符串
- JS 解析 XML,并更新局部页面
XMLHttpRequest 的用法
使用 XMLHttpRequest 三步骤:
- 要用 XMLHttpRequest 构造一个对象
- 调用 open() 方法
- 调用 send() 方法
open() 方法接收三个参数:请求类型,请求 url,是否使用异步;
send() 方法接受一个参数:请求主体发送的数据。
这个请求是同步的,浏览器会等到服务器响应之后继续执行,响应之后的相关属性:
responseText:响应主体返回的文本
status:响应的 HTTP 状态
statusText:响应的 HTTP 状态说明
在接收到响应后,应该这样检查两种状态
let request = new XMLHttpRequest()
request.onreadystatechange = function(e){
if(request.status >= 200 && request.status < 300 || request.status === 304){
console.log(request.responseText)
}else if(request.status >=400){
console.log("错误信息:" + request.status)
}
}
request.open('POST','http://jack.com:8889/xxx')
request.send()
大多数情况下,我们使用的是异步请求,才能 JS 继续执行,不必等待响应,此时应该检查readyState
,这个属性有5种取值:
值 | 状态 | 描述 |
---|---|---|
0 | UNSENT(未打开) | open()方法还未被调用 |
1 | OPENED(未发送) | send()方法还未被调用 |
2 | HEADERS_RECEIVED(以获取响应头) | send()方法已经被调用,响应头和响应状态已经返回 |
3 | LOADING(正在下载响应体) | 响应体下载中;responseText中已经获取部分数据 |
4 | DONE(请求完成) | 整个请求过程已完毕 |
只要readyState
属性值一变化,就会触发一次readystatechange
事件,可以利用这个事件来检测每次状态变化后的readystate
的属性值,通常我们只对readystate
值为4
进行检测。
let request = new XMLHttpRequest()
request.onreadystatechange = function(e){
if(request.readyState === 4){
if(request.status >= 200 && request.status <= 300){
console.log(request.responseText)
}else if(request.status >=400){
console.log("错误信息:" + request.status)
}
}
}
request.open('POST','http://jack.com:8889/xxx')
request.send()
响应返回的requestText
永远是字符串,早期使用的符合 XML 格式的字符串,现在使用的是符合 JSON 语法的字符串,前端拿到后可以用window.JSON.parse()
来解析
具体来看一个例子:点击按钮发送一个 POST 请求
myButton.addEventListener('click',function(){
let request = new XMLHttpRequest()
request.onreadystatechange = function(){ //尽量往上放,不会错过任何一个状态,放在下面的话会错过之前的状态
console.log(request.readyState)
if(request.readyState === 4){ //请求完成
if(request.status === 200){ //请求成功
let string = request.responseText
//把符合 JSON 语法的String 转换成 JS 对应的 Object
let object = window.JSON.parse(string) //JSON.parse 是浏览器提供的,json3.js是著名的就是写JSON.parse的
}else if(request.status === 400){ //请求失败
console.log("错误信息:" + request.status)
}
}
}
request.open('POST','http://jack.com:8889/xxx') //配置 request
request.send()
})
服务器上面就要这样写
if(path === '/xxx' && method === 'POST'){
response.setHeader('Content-Type','text/json;charset=utf-8')
response.write(` //JSON语法
{ //Http第四部永远是 String,这里是符合 JSON 语法的
String,不是 Object
"note":{
"to":"张三",
"from":"李四",
"heading":"打招呼",
"content":"hi"
}
}
`)
}
JavaScript 和 JSON 语法的不同之处
JS | JSON |
---|---|
undefined | 没有 |
null | null |
['a','b'] | ["a","b"] |
function{} | 没有 |
{name:'frank'} | {"name":"frank"} |
'frank' | "frank" |
var a = {};a.self = a | 搞不定(没有变量) |
{proto} | 没有原型链 |
跨域资源共享
Ajax 通信只能访问同一个域下的资源,简单的说如果不是同一个网站,不能送 AJAX 请求,它是状态码status
为0。
只有协议+端口+域名一模一样才允许发 AJAX 请求
因为 AJAX 可以读取响应内容,因此浏览器不允许你这样做
有时也需要合理的跨域请求,有两种方法:
- SRJ方案
- CORS方案
SRJ 方案之前已经讲过了,这里不在重复,可以看:JSONP技术栈
这里讲解一个 CORS(Cross-Origin Resource Sharing,跨域源资源共享),基本思想就是使用自定义的 HTTP 响应头:
在服务器上,共享的资源加上响应头
response.setHeader('Access-Control-Allow-Origin','http://jack.com:8889')
就可以了。
如果没有这个头部,或者有这个信息但源信息不匹配,请求还是成功,但服务器给的响应没有响应体(第四部分)。注意:请求和响应都不包含 Cookie 信息。