之前寫了一篇博客理解JSONP 上關(guān)于AJAX出現(xiàn)之前如何發(fā)請求
簡單回顧一下:
1.用 form 可以發(fā)請求括儒,缺點是會刷新頁面或新開頁面
form發(fā)送get請求:
輸入密碼后,點擊提交锐想,打開開發(fā)者工具可以看到一個get請求帮寻,點開找到Request Headers點擊view source
同樣可以用form發(fā)送post請求,與get請求區(qū)別是post請求沒有查詢參數(shù)
post請求的第四部分 password在下面的 Form Data 的view source 里
2.用 a 可以發(fā) get 請求赠摇,但是也會刷新頁面或新開頁面
點擊click就發(fā)送請求<a id="ada" href="/ada">click</a>
//運行一個腳本固逗,讓網(wǎng)頁自己點擊(但是依然會刷新頁面)
<script>
ada.click()
</script>
3.用 img 可以發(fā) get 請求,它不會刷新頁面藕帜,但是只能以圖片的形式展示
<script>
var image = document.createElement('img')
image.src = '/ada'
image.onload = function(){
console.log('succsee')
}
image.onerror = function(){
console.log('fail')
}
</script>
4.用 link 可以發(fā) get 請求烫罩,但是只能以 CSS、favicon 的形式展示
<script>
var link = document.createElement('link')
link.rel = 'stylesheet'
link.href = '/ada'
//需要將link放到頁面中才能發(fā)送請求
document.head.appendChild(link)
</script>
5.用 script 可以發(fā) get 請求洽故,但是只能以腳本的形式運行
<script>
var script = document.createElement('script')
script.src = "/ada"
//需要將script放到頁面中才能發(fā)送請求
document.head.appendChild(script)
</script>
當(dāng)然還有其他方法
有關(guān)AJAX的學(xué)習(xí)推薦阮一峰博客
微軟的突破
IE 5 率先在 JS 中引入 ActiveX 對象(API)贝攒,使得 JS 可以直接發(fā)起 HTTP 請求。
隨后 Mozilla时甚、 Safari隘弊、 Opera 也跟進(jìn)了,取名 XMLHttpRequest荒适,并被納入 W3C 規(guī)范
AJAX
Jesse James Garrett 將如下技術(shù)取名叫做 AJAX(Asynchronous JavaScript and XML):異步的 JavaScript 和 XML
1.使用 XMLHttpRequest 發(fā)請求
2.服務(wù)器返回 XML 格式的字符串
3.JS 解析 XML梨熙,并更新局部頁面
同樣我們用node服務(wù)器來嘗試一下這三個條件(AJAX)
新建html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
hi
</body>
</html>
Node代碼
console.log('含查詢字符串的路徑\n' + pathWithQuery)
if (path === '/') {
var string = fs.readFileSync('./index.html', 'utf8')
response.statusCode = 200
response.setHeader('Content-Type', 'text/html; charset=utf-8')
response.write(string)
response.end()
} else{
response.statusCode = 404
response.setHeader('Content-Type', 'text/html; charset=utf-8')
response.write('找不到服務(wù)器')
response.end()
}
對于HTTP來說,響應(yīng)的第四部分始終是string在 html 里創(chuàng)建一個button吻贿,引入當(dāng)前目錄下的 js 文件
<body>
<button id="myButton">點我</button>
<script src="./main.js"></script>
</body>
Node代碼//在原Node代碼中插入串结,下同
//注意這里是 /main.js 而不是 ./main.js,因為HTTP請求永遠(yuǎn)是絕對路徑
else if (path === '/main.js') {
//這里當(dāng)然是./main.js
var string = fs.readFileSync('./main.js', 'utf8')
response.statusCode = 200
response.setHeader('Content-Type', 'text/javascript; charset=utf-8')
response.write(string)
response.end()
}
首先滿足1.使用 XMLHttpRequest 發(fā)請求
myButton.addEventListener('click', (e) => {
let request = new XMLHttpRequest()
//初始化請求舅列,參數(shù)為:method,url,async(異步狀態(tài)下才是AJAX),user,password(后三個參數(shù)一般默認(rèn))
request.open('GET', '/ada')
request.send()
})
2.服務(wù)器返回 XML 格式的字符串
XML已經(jīng)不流行了肌割,但是我們依然可以嘗試一下
找一個一個XML example
else if (path === '/ada') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/xml; charset=utf-8')
response.write(`
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>`)
response.end()
}
3.JS 解析 XML,并更新局部頁面
瀏覽器是分步下載響應(yīng)的帐要,一般只要記住 readyState === 4 表示請求完成
可以用 onreadystatechange 監(jiān)聽 readyState
myButton.addEventListener('click', (e) => {
let request = new XMLHttpRequest()
request.onreadystatechange = () => {
if (request.readyState === 4) {
console.log('請求響應(yīng)都完成了')
if (request.status >= 200 && request.status < 300) {
console.log('success')
//響應(yīng)值在300-400之間瀏覽器會重新發(fā)送請求
} else if (request.status >= 400) {
console.log('fail')
}
}
}
//初始化請求把敞,參數(shù)為:method,url,async(異步狀態(tài)下才是AJAX),user,password(后三個參數(shù)一般默認(rèn))
request.open('GET', '/ada')
request.send()
})
如果把(path === '/ada'){}里改成400 //注意不要改錯地方
response.statusCode = 400
當(dāng)然會返回 fail,可以看到 readyState 是不受狀態(tài)碼影響的JS 是可以解析 XML的榨惠,但是現(xiàn)在XML已經(jīng)被JSON取代了奋早,我們可以簡單打印出來
console.log(request.responseText)
JSON
JSON是道格拉斯基于JavaScript發(fā)明的數(shù)據(jù)交換語言
-
特點:
- 只有 object盛霎、array、string耽装、number愤炸、true、false掉奄、null 這幾種類型
- 字符串首尾必須為雙引號
JS VS JSON
undefined/symbel 無
null null
['a','b'] ["a","b"]
function f(){} 無
{a:b} {"a","b"}
'hello world' "hello world"
var a = {}
a.self = a 無法做到{無變量等形式}
{__proto__} 沒有原型鏈
用JSON替換XML
Node代碼:
else if (path === '/ada') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/xml; charset=utf-8')
//變XML為JSON规个,key和value都可以替換成自己喜歡的
response.write(`
{
"note":{
"to": "reader",
"from": "Ada",
"heading": "greet",
"content": "hello word!"
}`)
response.end()
js完整代碼
myButton.addEventListener('click', (e) => {
let request = new XMLHttpRequest()
request.onreadystatechange = () => {
if (request.readyState === 4) {
console.log('請求響應(yīng)都完成了')
if (request.status >= 200 && request.status < 300) {
console.log('success')
console.log(typeof request.responseText)
console.log(request.responseText)
let string = request.responseText
// 把符合 JSON 語法的字符串轉(zhuǎn)換成 JS 對應(yīng)的值
let object = window.JSON.parse(string)
// JSON.parse 是瀏覽器提供的
//響應(yīng)值在300-400之間瀏覽器會重新發(fā)送請求
} else if (request.status >= 400) {
console.log('fail')
}
}
}
//初始化請求,參數(shù)為:method,url,async(異步狀態(tài)下才是AJAX),user,password(后三個參數(shù)一般默認(rèn))
request.open('GET', '/ada')
request.send()
})
同源政策
同源政策規(guī)定姓建,AJAX請求只能發(fā)給同源的網(wǎng)址诞仓,否則就報錯。
同源政策的目的速兔,是為了保證用戶信息的安全墅拭,防止惡意的網(wǎng)站竊取數(shù)據(jù)。
文章開頭提到的 form 和 a 等發(fā)送請求是沒有同源政策的涣狗,而AJAX是可以讀取響應(yīng)內(nèi)容的谍婉。
因此只有 協(xié)議+端口+域名 一模一樣(同源)才允許發(fā) AJAX 請求
如何規(guī)避同源政策?跨域
有關(guān)JSONP跨域在文章開頭提供我的博客舉過例子
這次我們用 CORS 跨域
什么是 CORS:Cross-Origin Resource Sharing(跨域資源共享)
同樣用理解JSONP 下博客中創(chuàng)建過的網(wǎng)站來舉例子
首先打開服務(wù)器端口
把請求路徑改為
request.open('GET', 'http://jack.com:8002/ada')
點擊點我
報錯了镀钓,因為不是同源屡萤,響應(yīng)完成卻得不到任何內(nèi)容
解決方法,在Node代碼中加入一句
//允許 http://ada.com:8001 訪問我
response.setHeader('Access-Control-Allow-Origin','http://ada.com:8001')
點擊點我掸宛,即可向 ada.com:8001 發(fā)送請求并返回 jack.com:8002/ada 的響應(yīng)內(nèi)容這就是用CORS實現(xiàn)AJAX跨域的過程
完整代碼詳見 github
本文僅供個人學(xué)習(xí)使用