1. 程式人生 > >http簡單認識及js操作http

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部分, 其重點就是新增實體, 新增首部欄位的操作。 而關於新增首部欄位呢, 就有必要明白各個首部欄位的意義了。