http簡單認識及js操作http
前言
這篇是我在看了《圖解http》, 並查閱了關於ajax相關知識之後, 感覺有所收穫, 所寫。 主要叫講述簡單http認識, js如何操作。, 關於CORS跨域等問題。
一、http基礎篇
簡介
http(超文字傳輸文字協議), 用於web應用傳輸資料的協議, 只能由客戶端發起, 由服務端響應。 具有無狀態等特點。
結構
http協議的傳輸單位是http報文(請求報文、響應報文)。 報文的結構可分為:請求/響應行、 首部欄位、實體部分。
get請求報文
GET /index.html HTTP/1.1 //請求行
Host: test.com //首部欄位
get響應報文
HTTP/1.1 200 OK //響應行
Date: Tue, 10 Jul 2012 06;50:15 GMT //首部欄位
Content-Length: 362 //首部欄位
Content-Type: text/html //首部欄位
<html> //實體
...
請求行用於說明請求方法 , 請求地址, http版本號
響應行用於說明伺服器http版本號, 響應狀態碼, 狀態碼的原因短句
首部欄位分為: 通用首部欄位、 請求首部欄位、 響應首部欄位、 實體首部欄位
對於實體內的內容, 可以用實體首部欄位加以說明。 最常使用的是content-type: xxxx, 說明實體內容的型別。
二、javaScript操作http
瀏覽器中, http請求可以由瀏覽器中的如下內容傳送:
1. 瀏覽器中的url位址列
2. 頁面有src屬性的標籤(img、script、 link等)
3. 帶有action屬性的form表單
4. XMLHttpRequest物件
1. XMLHttpRequest的基本用法
在這些方法中, XMLHttpRequest物件提供了介面讓我們操作http.基本用法如下:
var xhr = new XMLHttpRequest();//此時readyState屬性值為0
xhr.open('post', 'http://www.test.com', false)//此時readyState屬性值為1
xhr.send("name=yang&psd=123")//readyState屬性值為2
xhr.onreadyStatechange = function(){
if(xhr.readState === 4 && xhr.status === 200 ){
console.log(xhr.responseText)
}else{
console.log('Request was unsuccessfull:' + xhr.status)
}
}
以上是XMLHttpRequest的基本使用方法。
1). 傳送資料, 使用send方法
這裡的傳送資料指的是post方法傳送資料
xhr.send("name=yang&psd=123")//post方法傳送了一個form表單資料
如果是get方法則資料拼接到url後面(使用encodeURIComponent()將名和值進行編碼之後), send方法引數必須是null
xhr.open('get', 'http://www.test.com?name='yang'&psd=123, false)//將name和value進行encodeURIComponent編碼, (同cookie的value一樣), 其中open方法最後一個引數代表是否非同步
xhr.send(null)//不能不寫
2). 使用readyState可以檢視當前xhr物件的狀態, 狀態有:
- 0– 沒呼叫open方法
- 1– 沒呼叫send方法
- 2– 呼叫send方法, 未接受到響應
- 3– 正在接受響應, 未接受完成
- 4– 響應全部接受
3). 獲得響應的狀態, 使用status屬性, 當屬性的值為200表示請求成功
var httpStatus = xhr.status
if(httpStatus === 200){
//請求成功,可以做接下來的事情了
}
4). 獲得響應的資料,使用responseText屬性
var result = xhr.responseText
5). 新增首部欄位, 使用setRequestHeader方法
xhr.setRequestHeader('myHeader', 'myValue')//這裡必須放在open方法, 和send方法中間, 否則不能成功新增首部欄位
6). 獲得首部欄位, 使用getResponseHeader或getAllResponseHeaders方法
var header = xhr.getResponseHeader('myHeader')//傳入首部欄位名
var headers = xhr.getAllResponseHeader()//獲得全部的首部欄位,返回多行文字內容
//這是headers的結果
Date: Sun, 14 Nov 2004 18:04:03 GMT
Server: Apache/1.3.29(Unix)
Vary: Accept
X-Powered-By: PHP/4.3.8
Connection: close
Content-Type: text/html;charset=ios-8859-1
2. XMLHttpRequest跨域用法
使用XHR物件通訊,有一個限制就是跨域安全策略。 預設情況下, XHR對下只能訪問包含它的頁面位於同一個域中的資源。 但是有時我們開發不能不進行跨域請求。
1). CORS跨域源資源共享
基本思想: 使用自定義的首部欄位讓給瀏覽器與伺服器溝通, 從而決定請求或響應是否應該成功。
整個CORS通訊過程,都是瀏覽器自動完成,不需要使用者參與。對於開發者來說,CORS通訊與同源的AJAX通訊沒有差別,程式碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動新增一些附加的頭資訊(Origin首部欄位),有時還會多出一次附加的請求,但使用者不會有感覺。
2). 原理
客戶端
瀏覽器一旦發現AJAX請求跨源,就會自動新增一些附加的頭資訊(Origin首部欄位),有時還會多出一次附加的請求(分簡單請求),但使用者不會有感覺。
服務端
伺服器讀取Origin首部欄位的值, 判斷是否應該成功, 如果成功返回的響應報文中首部欄位包含Access-control-allow-Origin:xxxxxx。 如果xxxxx為*或與自己傳送的Origin的值相同, 瀏覽器就會判斷請求成功。
3). CORS的簡單請求與非簡單請求
侷限
CORS跨域請求, 存在以下限制, 例如:
- 求方法為post/get/head,
- 首部欄位只設置Content-Type
- 不能訪問響應頭部
- cookie不隨請求傳送
簡單情求
請求方法為post/get/head, 首部欄位只設置content-type(只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain等
), 這樣的請求為簡單請求。 這是瀏覽器將會在請求報文中新增Origin的首部欄位,完成情趣。
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
非簡單請求
如果不是簡單請求, 瀏覽器將不會想處理簡單請求一樣處理, 例如我們希望新增其他的首部欄位。 這瀏覽器將會發送一個預檢請求(Preflighted Requests)
Preflighted Requests,如下
OPTIONS /cors HTTP/1.1 //請求的方法, 地址, http版本
Origin: http://api.bob.com // 客戶端的域名
Access-Control-Request-Method: PUT //即將發起非簡單請求的方法, 用於伺服器判斷是否支援該方法
Access-Control-Request-Headers: X-Custom-Header //即將發起非簡單請求攜帶的首部欄位, 用於伺服器判斷是否支援該欄位
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
這種請求的方法是options方法, 用於伺服器詢問。 如果服務都滿足, 將會如下
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com //允許跨域的域
Access-Control-Allow-Methods: GET, POST, PUT //支援的請求方法
Access-Control-Allow-Headers: X-Custom-Header //支援的頭部
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
瀏覽器將會用響應報文的首部欄位中以Access-control開頭的欄位與即將傳送的請求比對, 如果服務將會如同簡單請求一樣傳送請求。 故,非簡單請求會有一個預檢請求。
同時, 瀏覽器會將響應按照這個時間:(Access-Control-Max-Age: 1728000)儲存, 在該時間未過期期間, 就不必傳送預檢請求, 而直接發起請求。
攜帶cookie
預設情況下, 跨域請求不會攜帶cookie。 需要我們設定一個屬性值–withCredentials
xhr.withCredentials = true
當然跨域攜帶cookie也需要伺服器支援才行, 如果服務願意接受攜帶cookie的跨域資訊, 就會在預檢請求響應頭部新增如下首部欄位:
Access-Control-Allow-Credentials: true
3. 跨瀏覽器的CORS
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest()
if("withCredentials" in xhr){
xhr.open(method, url, true);
}else if (typeof XDomainRequest() != 'undefined') {
xhr = new XDomainRequest()
xhr.open(method, url)
}else{
xhr = null
}
return xhr
}
var request = createCORSRequest('get', 'http://test.com')
if(request){
request.onload = function(){//XMLHttpRequest 2級增加的事件
//對request.responseText進行處理
}
request.send(null)
}
總結
詳細瞭解http呢是有必要的, 對於我們理解很多東西都有非常大的好處。 比如這篇文章, 關於操作http部分, 其重點就是新增實體, 新增首部欄位的操作。 而關於新增首部欄位呢, 就有必要明白各個首部欄位的意義了。