AJAX 是什么鬼

之前寫了一篇博客理解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í)使用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市招拙,隨后出現(xiàn)的幾起案子唧瘾,更是在濱河造成了極大的恐慌,老刑警劉巖别凤,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饰序,死亡現(xiàn)場離奇詭異,居然都是意外死亡规哪,警方通過查閱死者的電腦和手機(jī)求豫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诉稍,“玉大人蝠嘉,你說我怎么就攤上這事”蓿” “怎么了蚤告?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長服爷。 經(jīng)常有香客問我杜恰,道長获诈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任心褐,我火速辦了婚禮舔涎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逗爹。我一直安慰自己亡嫌,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布桶至。 她就那樣靜靜地躺著昼伴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪镣屹。 梳的紋絲不亂的頭發(fā)上圃郊,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機(jī)與錄音女蜈,去河邊找鬼持舆。 笑死,一個胖子當(dāng)著我的面吹牛伪窖,可吹牛的內(nèi)容都是我干的逸寓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼覆山,長吁一口氣:“原來是場噩夢啊……” “哼竹伸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起簇宽,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤勋篓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后魏割,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體譬嚣,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年钞它,在試婚紗的時候發(fā)現(xiàn)自己被綠了拜银。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡遭垛,死狀恐怖尼桶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锯仪,我是刑警寧澤疯汁,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站卵酪,受9級特大地震影響幌蚊,放射性物質(zhì)發(fā)生泄漏谤碳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一溢豆、第九天 我趴在偏房一處隱蔽的房頂上張望蜒简。 院中可真熱鬧,春花似錦漩仙、人聲如沸搓茬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卷仑。三九已至,卻和暖如春麸折,著一層夾襖步出監(jiān)牢的瞬間锡凝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工垢啼, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留窜锯,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓芭析,卻偏偏與公主長得像锚扎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子馁启,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容