前言:
预习:http://javascript.ruanyifeng.com/bom/ajax.html
金句:
- 你才返回对象,你全家都返回对象
- JS 是一门语言,JSON 是另一门语言,JSON 这门语言抄袭了 JS这门语言
- AJAX 就是用 JS 发请求
- 响应的第四部分的类型是字符串,可以用 JSON 语法表示一个对象,也可以用 JSON 语法表示一个数组,还可以用 XML 语法,还可以用 HTML 语法,还可以用 CSS 语法,还可以用 JS 语法,还可以用.........
回顾上一节:
如何发请求?
用 form 可以发请求,但是会刷新页面或新开页面
用 a 可以发 get 请求,但是也会刷新页面或新开页面
用 img 可以发 get 请求,但是只能以图片的形式展示
用 link 可以发 get 请求,但是只能以 CSS、favicon 的形式展示
用 script 可以发 get 请求,但是只能以脚本的形式运行
有没有什么方式可以实现:
get、post、put、delete 请求都行;
想以什么形式展示就以什么形式展示;
本节,将介绍一种方法,可以解决上面问题。
一、用XMLHttpRequest发请求
-
XMLHttpRequest的产生:IE 5 率先在 JS 中引入 ActiveX 对象(API),使得 JS 可以直接发起 HTTP 请求。随后 Mozilla、 Safari、 Opera 也跟进(抄袭)了,取名 XMLHttpRequest,并被纳入 W3C 规范。
XMLHttpRequest 是window 下的一个全局对象,也是一个构造函数。
image.png
二、AJAX
Jesse James Garrett 将如下技术取名叫做 AJAX:异步的 JavaScript 和 XML;
一个完整的AJAX要具备以下3点:
- 使用 XMLHttpRequest 发请求
- 服务器返回 XML 格式的字符串
- JS 解析 XML,并更新局部页面
尝试用JS写一个符合上面3点要求的请求:
server-ajax.js:
}else if(path === '/xxx'){
response.setHeader('Content-Type','application/xml')
response.statusCode = 200
response.write(`
<note>
<to>小明</to>
<from>老王</from>
<heading>问候</heading>
<body>Hi,我在你隔壁</body>
</note>
`)
response.end()
}
html:
<body>
<h5>你的账户余额是:<span id="amount">&&&amount&&&</span></h5>
<button id="button">付款1块钱</button>
<script>
button.addEventListener('click',(e)=>{
let request = new XMLHttpRequest() //1-构造一个XMLHttpRequest
request.onreadystatechange = ()=>{ //监听readystate的变化
if(request.readyState === 4){
console.log('请求响应完毕')
if(request.status >= 200 && request.status < 300 ){
console.log('请求成功')
console.log(request.responseText)
let parser = new DOMParser()
let xmlDoc = parser.parseFromString(request.responseText,"text/xml")
let title = xmlDoc.getElementsByTagName('heading')[0].textContent
console.log(title)
}else if(request.status >= 400){
console.log('请求失败')
}
}
}
// console.log(request.readyState) //结果:0
request.open('GET','/xxx') //2-设定request,请求方式,URL,是否异步...,默认是异步;即便实际请求的文件路径为'./xxx'但是http在发请求是还是会强制变更为符合http的路径(绝对路径),
// console.log(request.readyState) //结果:1
request.send() //3-发送请求
// setInterval(()=>{
// console.log(request.readyState)
// },1) //结果:1, 4;中间状态未能捕捉到
})
</script>
</body>
以上的就是一个符合AJAX的完整的JS代码。
将其整理修剪后的简洁的代码:
<script type="text/javascript">
let ajaxRequest = new XMLHttpRequest()
ajaxRequest.open('get','/xxx')
ajaxRequest.send()
ajaxRequest.onreadystatechange = ()=>{
if (ajaxRequest.readyState ==== 4) {
if (ajaxRequest.status >= 200 && ajaxRequest.status < 300) {
let string = ajaxRequest.responseText
let object = window.JSON.parse(string)
}
}
}
</script>
-
XMLHttpRequest.readyState
XMLHttpRequest.readyState 属性返回一个 XMLHttpRequest 代理当前所处的状态。一个 XHR 代理总是处于下列状态中的一个:
值 | 状态 | 描述 |
---|---|---|
0 | UNSENT | 代理被创建,但尚未调用 open() 方法。 |
1 | OPENED | open() 方法已经被调用。 |
2 | HEADERS_RECEIVED | send() 方法已经被调用,并且头部和状态已经可获得。 |
3 | LOADING | 下载中; responseText 属性已经包含部分数据 |
4 | DONE | 下载操作已完成。 |
三、XML和JSON
-
JSON-----JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
JSON是一门新语言,并不是一个JavaScript对象,只不过是仿JavaScript编写的。
JSON的数据格式规范----JSON官网-
JSON VS JS
- JSON只有 string,number,object,array,true,false,null 这7种类型。JavaScript的基本类型中,undefined,symbol,function这3种没有抄;
- JSON 的字符串首尾必须是双引号:"";
-
JSON VS JS
举例:
JS | VS | JSON |
---|---|---|
undefined | 没有 | |
null | null | |
['a',"b"] | ["a","b"] | |
function fn(){} | 没有 | |
var a={};a.self=a; |
搞不定,没有变量 | |
{__proto__} |
没有原型链 |
2. XML 与 JSON
来个例子:
返回XML格式的字符串:
response.setHeader('Content-Type','application/xml;charset=utf-8')
response.write(`
<note>
<to>小明</to>
<from>老王</from>
<heading>问候</heading>
<body>Hi,我在你隔壁</body>
</note>
`)
返回JSON格式的字符串:
response.setHeader('Content-Type','application/json;charset=utf-8')
response.write(`
{
"note":{
"to":"小明",
"from":"老王",
"heading":"问候",
"body":"Hi,我在你隔壁"
}
}
`)
以上两种返回的内容在类型上都是字符串,只是书写格式符合XML和JSON;也就是说前端收到的都只是一堆字符串。
那么,前端如何以符合XML和JSON的格式应用这一堆字符串??
<script type="text/javascript">
button.addEventListener('click',(e)=>{
let request = new XMLHttpRequest()
request.onreadystatechange = ()=>{
if(request.readyState === 4){
console.log('请求响应完毕')
if(request.status >= 200 && request.status < 300 ){
console.log('请求成功')
console.log(typeof request.responseText) //string
console.log(request.responseText)
// let parser = new DOMParser()
// let xmlDoc = parser.parseFromString(request.responseText,"text/xml")
// let title = xmlDoc.getElementsByTagName('heading')[0].textContent
// console.log(title)
let string = request.responseText
// 把符合 JSON 语法的字符串
// 转换成 JS 对应的值
let object = window.JSON.parse(string)
// JSON.parse 是浏览器提供的
// document.getElementById 是浏览器提供的
console.log(typeof object) //此时已经是 Object
console.log(object)
}else if(request.status >= 400){
console.log('请求失败')
}
}
}
request.open('GET','/xxx')
request.send()
})
</script>
四、同源策略与CORS跨域
-
问题:为什么form表单提交没有跨域问题,而ajax提交有跨域问题???
测试:
- 用form表单发一个跨网站的请求(记得勾选preserve log):
<body>
<form action="https://www.baidu.com" method="GET">
<input type="password" name="password">
<input type="submit">
</form>
</body>
测试1结果:点击提交后,页面跳转https://www.baidu.com,响应状态码为200,成功,如果是用POST,百度会响应302;
- 用AJAX发一个跨网站的请求(记得勾选preserve log):
<script type="text/javascript">
let ajaxRequest = new XMLHttpRequest()
ajaxRequest.open('get','https://www.baidu.com')
ajaxRequest.send()
ajaxRequest.onreadystatechange = ()=>{
if (ajaxRequest.readyState ==== 4) {
console.log('请求响应完毕')
console.log(request.status)
if (ajaxRequest.status >= 200 && ajaxRequest.status < 300) {
let string = ajaxRequest.responseText
let object = window.JSON.parse(string)
}
}
}
</script>
测试2结果:点击提交后,页面并没有跳转到https://www.baidu.com,但是响应状态码为200,请求成功;查看响应内容发现为空;打印status结果为0;控制台有报错:
这就是AJAX的同源策略导致的结果;form,img,a,script,link都可以跨站请求,只有ajax只能同源请求,原因????
因为原页面用 form 提交到另一个域名之后,页面会跳转到新页面,原页面就死了,原页面的脚本无法获取新页面的内容。
所以浏览器认为这是安全的。
而 AJAX 是可以读取响应内容的,因此浏览器不允许你这样做;
如果你细心的话会发现,其实请求已经发送出去了,只是拿不到响应而已。
所以,浏览器的这个策略的本质是,一个域名的JS,在未经允许的情况下,不得读取另一个域名的内容。但浏览器并不阻止你向另一个域名发送请求。
-
同源策略
只有 协议+域名+端口 一模一样,才允许发AJAX请求。
测试1:http://baidu.com 可以向 http://www.baidu.com 发AJAX请求吗?
测试1:http://baidu.com:80 可以向 http://baidu.com:81 发AJAX请求吗?
怎么解决跨站?????
-
CORS----跨域资源共享(Cross-origin resource sharing)
frank.com:8001 的前端想要 跨站请求 jack.com:8002 的后台数据, 只需在jack.com的后端的响应里添加一句:response.setHeader('Access-Control-Allow-Origin','https://frank.com:8001')
。
网友评论