可以如何發送請求
-
用
<form>
可以發請求,但是會刷新頁面或新開頁面<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 請求都行,想以什麼形式展示就以什麼形式展示❓
ajax
Asynchronous Javascript And XML
異步 Javascript 和 XML
需要滿足下面三個條件,可以稱之爲 ajax:
- 使用 XMLHttpRequest 發請求
- 服務器返回 XML 格式的字符串
- JS 解析 XML,並更新局部頁面
不過隨着技術發展,XML 越來越不常用,經常使用 JSON 代替 XML
version1.0
我們嘗試做一個按鈕,點擊向服務器發送一個請求
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 :
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;最後,發送請求。
當服務器收到請求了 /xxx 路徑,然後,就返回了一串格式符合 XML 的字符串
並且,當請求和響應進行到各個狀態時,都會打印出它的狀態碼
(狀態碼請參考:https://developer.mozilla.org...)
version2.0-獲取xml
除了可以獲取狀態碼、在瀏覽器控制檯獲取服務器返回的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(); //發送請求
})
version3.0-JSON
由於 xml 看上去不夠簡潔,而且實際使用中,獲取的方式比較繁瑣(參考上面的三句 let),所以,發明了一個新的數據格式化語言——JSON,用以替代 xml。
(JSON參考官網:http://www.json.org/)
JSON vs. Javascript:
- 沒有 function,undefined
- 字符串首尾必須是雙引號 ""
- 沒有 變量
- 沒有 原型鏈
修改後端代碼,使其返回一個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(); //發送請求
})
同源策略&CORS跨域
和<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
使用Javascript發送任意格式的請求
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
- 第一部分:request.open('get','/xxx')
- 第二部分:request.setHeader('Content-type','x-www-form-urlencoded')
- 第四部分:request.send('a=1&b=2')
使用 JS 獲取任意響應 header
- 第一部分:request.status / request.statusText
- 第二部分:request.getResponseHeader() / request.getAllResponseHeaders()
- 第四部分:request.responseText
封裝ajax
我們的目標是隻使用一個函數,就能實現下面發送請求的功能:
- request.open('GET','/xxx');
- request.onreadystatuschange=function(){}
- request.send('雖然我是GET,但我也有請求體');
version1.0
封裝後的前端代碼:
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封裝在一個函數裏,之後調用只需要調用一個函數,出入響應的參數就能實現發送請求的功能。
version2.0
上個版本封裝的很好,但是有幾個問題:
- 需要傳入的參數太多,可能是不是會忘了需要傳入什麼參數,無法快速的知道參數含義
- 當有一個參數用戶不想傳入的時候,只能使用
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(){}
}
)
})
version3.0
我們還需要封裝發送請求頭:
再次修改封裝後的前端代碼:
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使用ajax
請參考jQuery文檔:https://api.jquery.com/jQuery...
題外話
計算代碼執行時間
下列代碼可以計算從console.time()
到console.timeEnd()
之間代碼執行的時間
console.time()
//your code
console.timeEnd()
結構化編程:
- 順序執行
- if...else...
- while/for
ES6解構賦值
使用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
聲明!!!
version4.0-Promise
當用戶要使用很多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的輸入,直接處理
})