用<form>
能夠發請求,可是會刷新頁面或新開頁面html
<form action='xxx' method='get'> <input type='password' name='password'> <input type='submit'> </form>
<a>
只能夠發 get 請求,可是也會刷新頁面或新開頁面<img>
只能夠發 get 請求,可是隻能以圖片的形式展現<link>
只能夠發 get 請求,可是隻能以 CSS、favicon 的形式展現<script>
只能夠發 get 請求,可是隻能以腳本的形式運行❓有沒有什麼方式能夠實現:get、post、put、delete 請求都行,想以什麼形式展現就以什麼形式展現❓前端
Asynchronous Javascript And XML
異步 Javascript 和 XMLjquery
須要知足下面三個條件,能夠稱之爲 ajax:ajax
不過隨着技術發展,XML 愈來愈不經常使用,常用 JSON 代替 XML編程
咱們嘗試作一個按鈕,點擊向服務器發送一個請求json
html :後端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>ajax_html</title> </head> <body> <button id='myButton'>點我</button> </body> <script src='./main.js'></script> </html>
main.js :api
myButton.addEventListener=('click',function(e){ var request= new XMLHttpRequest(); //新建請求 request.onreadystatuschange=function(){ //當請求的狀態有變化時,打印出狀態碼 console.log(request.readyStatus); } request.open('GET','/xxx'); //初始化,GET 方法,/xxx 路徑 request.send(); //發送請求 })
後端代碼 :跨域
}else if(path==='/xxx'){ response.statusCode = 200 response.setHeader('Content-Type', 'text/xml;charset=utf-8') response.write(` //xml <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> </note> `) response.end() }
效果 :
當點擊 點我 按鈕時,首先,新建一個XMLHttpRequest
請求;其次,使用 GET 方法請求到 /xxx;最後,發送請求。promise
當服務器收到請求了 /xxx 路徑,而後,就返回了一串格式符合 XML 的字符串
而且,當請求和響應進行到各個狀態時,都會打印出它的狀態碼
(狀態碼請參考:https://developer.mozilla.org...)
除了能夠獲取狀態碼、在瀏覽器控制檯獲取服務器返回的XML字符串外,還能夠將XML字符串轉換爲XML。
而且可使用DOM獲取元素的API,來獲取XML的元素,例如getElementByTagNames
...
修改後的 main.js 以下所示,新增內容和註釋如👈👇所指。
main.js :
myButton.addEventListener=('click',function(e){ var request= new XMLHttpRequest(); //新建請求 request.onreadystatuschange=function(){ console.log(request.readyStatus); //當請求的狀態有變化時,打印出狀態碼 if(request.readyStatus === 4){ 👈//表示請求響應都已經完成 if(request.status === 200){ 👈//表示服務器返回成功 👇//下面三句 let 用來獲取返回的 xml,而再也不是以前字符串格式 let parser = new DOMParser(); 👇//返回的內容能夠用 responseText 獲取 let xmlDoc = parser.parseFromString(request.responseText,'text/xml'); let title = xmlDoc.getElementsByTagNames('heading')[0].textContent; } } } request.open('GET','/xxx'); //初始化,GET 方法,/xxx 路徑 request.send(); //發送請求 })
因爲 xml 看上去不夠簡潔,並且實際使用中,獲取的方式比較繁瑣(參考上面的三句 let),因此,發明了一個新的數據格式化語言——JSON,用以替代 xml。
(JSON參考官網:http://www.json.org/)
JSON vs. Javascript:
修改後端代碼,使其返回一個JSON,👈👇爲修改處。
後端代碼 :
}else if(path==='/xxx'){ response.statusCode = 200 response.setHeader('Content-Type', 'text/json;charset=utf-8') //👈xml修改爲json response.write(` //json //👈👇返回json而不是xml { "note":{ "to":"Tove", "from":"Jani", "heading":"Reminder", "body":"Don`t forget me this weekend!" } } `) response.end() }
因爲服務器返回的只能是一個字符串(響應第4部分只能是字符串),因此,咱們也須要將返回的JSON字符串轉換爲一個對象,方便操做。
接下來,可使用js對對象的操做,獲取json的內容。
修改後的前端代碼,👈爲修改處。
main.js :
myButton.addEventListener=('click',function(e){ var request= new XMLHttpRequest(); //新建請求 request.onreadystatuschange=function(){ console.log(request.readyStatus); //當請求的狀態有變化時,打印出狀態碼 if(request.readyStatus === 4){ //表示請求響應都已經完成 if(request.status === 200){ //表示服務器返回成功 console.log("請求成功"); let string=request.responseText; 👈//獲取服務器返回的字符串 let jsonObject=window.JSON.parse(string); 👈//將返回的字符串變成對象 console.log(jsonObject.note); 👈//輸出對象裏的note console.log(jsonObject.note.from); 👈//輸出對象裏的note裏的from } } } request.open('GET','/xxx'); //初始化,GET 方法,/xxx 路徑 request.send(); //發送請求 })
和<form>
表單提交內容不同,AJAX不刷新頁面,而且能夠讀取響應內容,因此被瀏覽器認爲是不安全的,
因此:
只有 協議+域名+端口 如出一轍的時候,才容許發送AJAX請求
Σ(っ °Д °;)っ
那要是我必須須要另外一個網站的接口怎麼辦???
若是http://www.kitty.com
想要訪問http://www.ben.com
的一個接口,那Ben只須要在後端代碼里加上一句話,告訴瀏覽器,http://www.kitty.com
和http://www.ben.com
是友好關係,能夠互相訪問。
Ben的後端代碼:
}else if(path==='/xxx'){ //請求的接口 response.statusCode = 200 //返回狀態碼 response.setHeader('Content-Type', 'text/json;charset=utf-8') //設置返回類型爲json 👇//此句開啓友好模式 response.setHeader('Access-Control-Allow-Origin', 'http://www.kitty.com') response.write(` //json { "note":{ "to":"Tove", "from":"Jani", "heading":"Reminder", "body":"Don`t forget me this weekend!" } } `) response.end() }
添加response.setHeader('Access-Control-Allow-Origin', 'http://www.kitty.com')
,瀏覽器就知道,Kitty和Ben是好朋友,能夠互相訪問啦!!!
上述方法稱之爲:
Cross-Origin Resource Sharing → CORS
AJAX還容許用戶使用Javascript設置一個請求的任意部分,而且能夠獲取一個響應的任意部分。
一個請求:
GET /xxx HTTP/1.1 //第一部分,方法、地址、協議、協議版本號 HOST: //第二部分,包含不少行,包含不少內容 Content-Type: //第二部分,包含不少行,包含不少內容 //第三部分,一個回車 這裏是請求體 //第四部分
一個響應:
Http/1.1 200 OK //第一部分,協議、協議版本號、狀態碼、狀態信息 Content-Type: //第二部分, //第三部分,一個回車 這裏是響應體 //第四部分
發送一個任意的請求&獲取一個響應任意部分:
myButton.addEventListener=('click',function(e){ var request= new XMLHttpRequest(); //新建請求 request.open('GET','/xxx'); //設置請求第一部分:方法、路徑 request.setRequestHeader('Content-Type','x-www-form-urlencoded); //設置請求第二部分 request.send('雖然我是GET,但我也有請求體'); //設置請求第四部分 request.onreadystatuschange=function(){ console.log(request.readyStatus); //當請求的狀態有變化時,打印出狀態碼 if(request.readyStatus === 4){ //表示請求響應都已經完成 if(request.status === 200){ //表示服務器返回成功 console.log("請求成功"); console.log(request.status) //獲取響應第一部分,狀態碼 console.log(request.statusText) //獲取響應第一部分,狀態信息 console.log(request.getResponseHeader('Content-Type')) //獲取響應第二部分 console.log(request.getAllResponseHeaders); //獲取全部響應第二部分 console.log(request.responseText); //獲取響應第四部分 } } } })
總結:
總之,就是AJAX容許用戶使用Javascript設置任意一個請求(瀏覽器不讓設置的內容不能設置),也能獲取一個響應的任意部分。
使用 JS 設置任意請求 header
使用 JS 獲取任意響應 header
咱們的目標是隻使用一個函數,就能實現下面發送請求的功能:
封裝後的前端代碼:
window.jquery=function(){} window.$=window.jquery; window.jquery.ajax=function(url,method,body,successFn,failFn){ var request = new XMLHttpRequest(); //新建請求 request.open(method,url); 👈//傳入發送請求方式、請求地址 request.send(body); 👈//傳入請求體 request.onreadystatuschange=function(){ console.log(request.readyStatus); //當請求的狀態有變化時,打印出狀態碼 if(request.readyStatus === 4){ //表示請求響應都已經完成 if(request.status === 200){ //表示服務器返回成功 successFn.call(undefined,request.responseText); 👈//響應成功,調用傳入的成功函數 }else if(request.status >= 400){ failFn.call(undefined,request); 👈//相應失敗,調用傳入的失敗函數 } } } } myButton.addEventListener=('click',function(e){ window.jquery.ajax( '/xxx', 'GET', '雖然我是GET,但我也有請求體' function(){}, function(){} ) })
實現的功能是同樣的,只是將ajax封裝在一個函數裏,以後調用只須要調用一個函數,出入響應的參數就能實現發送請求的功能。
上個版本封裝的很好,可是有幾個問題:
null
進行佔位,很麻煩因此,咱們想到,給它傳入一個集成的參數,把須要的參數都放在一個對象裏,這樣能夠給參數指定名字,調用時,能夠調用對象裏的名字。
修改封裝後的前端代碼:
window.jquery=function(){} window.$=window.jquery; window.jquery.ajax=function(option){ 👈//由原來的傳入一個個的參數,變爲傳入包含全部參數的對象 👇//首先獲取參數對象裏的各個值 let url=option.url; let method=option.method; let body=option.body; let successFn=option.successFn; let failFn=option.failFn; var request = new XMLHttpRequest(); //新建請求 request.open(method,url); //傳入發送請求方式、請求地址 request.send(body); //傳入請求體 request.onreadystatuschange=function(){ console.log(request.readyStatus); //當請求的狀態有變化時,打印出狀態碼 if(request.readyStatus === 4){ //表示請求響應都已經完成 if(request.status === 200){ //表示服務器返回成功 successFn.call(undefined,request.responseText); //響應成功,調用傳入的成功函數 }else if(request.status >= 400){ failFn.call(undefined,request); //相應失敗,調用傳入的失敗函數 } } } } myButton.addEventListener=('click',function(e){ window.jquery.ajax( 👇//由原來的傳入一個個的參數,變成如今傳入一個包含全部參數的對象 { url: '/xxx', method: 'GET', body: '雖然我是GET,但我也有請求體' successFn: function(){}, failFn: function(){} } ) })
咱們還須要封裝發送請求頭:
再次修改封裝後的前端代碼:
window.jquery=function(){} window.$=window.jquery; window.jquery.ajax=function(option){ //由原來的傳入一個個的參數,變爲傳入包含全部參數的對象 //首先獲取參數對象裏的各個值 let url=option.url; let method=option.method; let body=option.body; let successFn=option.successFn; let failFn=option.failFn; let headers=option.headers; 👈//獲取參數對象裏的headers 👇//遍歷headers,將裏面的鍵、值都設置在請求頭裏 for(let key in headers){ let value=headers[key]; request.setRequestHeader(key,value); } var request = new XMLHttpRequest(); //新建請求 request.open(method,url); //傳入發送請求方式、請求地址 request.send(body); //傳入請求體 request.onreadystatuschange=function(){ console.log(request.readyStatus); //當請求的狀態有變化時,打印出狀態碼 if(request.readyStatus === 4){ //表示請求響應都已經完成 if(request.status === 200){ //表示服務器返回成功 successFn.call(undefined,request.responseText); //響應成功,調用傳入的成功函數 }else if(request.status >= 400){ failFn.call(undefined,request); //相應失敗,調用傳入的失敗函數 } } } } myButton.addEventListener=('click',function(e){ window.jquery.ajax( 👇//在參數對象裏傳入headers,裏面包括了想要設置的請求頭的鍵、值 { url: '/xxx', method: 'GET', headers: { 'content-type': 'application/x-www-form-urlencoded', 'color': 'red' } body: '雖然我是GET,但我也有請求體' successFn: function(){}, failFn: function(){} } ) })
請參考jQuery文檔:https://api.jquery.com/jQuery...
下列代碼能夠計算從console.time()
到console.timeEnd()
之間代碼執行的時間
console.time() //your code console.timeEnd()
使用ES6解構賦值新語法能夠簡化下列代碼:
window.jquery.ajax=function(option){ let url=option.url; let method=option.method; let body=option.body; let successFn=option.successFn; let failFn=option.failFn; let headers=option.headers; //your code }
解構以後:
window.jquery.ajax=function(option){ let {url,method,body,successFn,failFn,headers}=option; //your code }
更加高級點:
window.jquery.ajax=function({url,method,body,successFn,failFn,headers}){ //your code }
👆直接從window.jquery.ajax=function(){}
的第一個參數裏解構,並用let
聲明!!!
當用戶要使用不少ajax的時候,用i定義的或者別人自定義的,這樣,每一個人ajax的接口名稱都不同,用起來很麻煩,這時候,咱們可使用Promise技術
使用Promise和then:
👆👇爲修改處
window.jquery=function(){} window.$=window.jquery; window.jquery.ajax=function({url,method,body,headers}){ 👆//使用ES6解構新語法,而且刪除了successFn、failFn 👇//promise和以後使用ajax時的then一塊兒,能夠自動判斷成功函數和失敗函數 return new Promise(function(resolve,reject){ //遍歷headers,將裏面的鍵、值都設置在請求頭裏 for(let key in headers){ let value=headers[key]; request.setRequestHeader(key,value); } var request = new XMLHttpRequest(); //新建請求 request.open(method,url); //傳入發送請求方式、請求地址 request.send(body); //傳入請求體 request.onreadystatuschange=function(){ console.log(request.readyStatus); //當請求的狀態有變化時,打印出狀態碼 if(request.readyStatus === 4){ //表示請求響應都已經完成 if(request.status === 200){ //表示服務器返回成功 👇//響應成功,調用傳入的成功函數,修改sucessFn爲resolve resolve.call(undefined,request.responseText); }else if(request.status >= 400){ 👇//響應成功,調用傳入的成功函數,修改failFn爲reject reject.call(undefined,request); //相應失敗,調用傳入的失敗函數 } } } }) } myButton.addEventListener=('click',function(e){ window.jquery.ajax( //在參數對象裏傳入headers,裏面包括了想要設置的請求頭的鍵、值 { url: '/xxx', method: 'GET', headers: { 'content-type': 'application/x-www-form-urlencoded', 'color': 'red' } body: '雖然我是GET,但我也有請求體' } ).then(function(){},function(){}) 👆//這就是promise,就是在ajax後面加上then, 👆//傳入第一個函數會被當成是成功時調用的函數,第二個函數會被當成失敗時調用的函數 })
若是須要屢次處理:
//your code myButton.addEventListener=('click',function(e){ window.jquery.ajax( //在參數對象裏傳入headers,裏面包括了想要設置的請求頭的鍵、值 { url: '/xxx', method: 'GET', headers: { 'content-type': 'application/x-www-form-urlencoded', 'color': 'red' } body: '雖然我是GET,但我也有請求體' } ).then( function(){ //your code return xxx; }, function(){}) .then( function(){}, function(){}) 👆//這就是promise,就是在ajax後面加上then, 👆//傳入第一個函數會被當成是成功時調用的函數,第二個函數會被當成失敗時調用的函數 👆//當須要屢次調用,能夠在then的函數裏直接return,return的內容會被當成以後then的輸入,直接處理 })