1. 程式人生 > >HTTP協議和WEB框架

HTTP協議和WEB框架

英文 超文本 缺省值 通信速度 ever hand 頭部 end 接受

一、HTTP協議

一、HTTP簡介

  HTTP協議是Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫,是用於從萬維網(WWW:World Wide Web )服務器傳輸超文本到本地瀏覽器的傳送協議。

  HTTP是一個基於TCP/IP通信協議來傳遞數據(HTML 文件, 圖片文件, 查詢結果等)。

  HTTP是一個屬於應用層的面向對象的協議,由於其簡捷、快速的方式,適用於分布式超媒體信息系統。它於1990年提出,經過幾年的使用與發展,得到不斷地完善和擴展。目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的規範化工作正在進行之中,而且HTTP-NG(Next Generation of HTTP)的建議已經提出。

  HTTP協議工作於客戶端-服務端架構為上。瀏覽器作為HTTP客戶端通過URL向HTTP服務端即WEB服務器發送所有請求。Web服務器根據接收到的請求後,向客戶端發送響應信息。

  技術分享圖片

二、HTTP特點

  1、簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。每種方法規定了客戶與服務器聯系的類型不同。

由於HTTP協議簡單,使得HTTP服務器的程序規模小,因而通信速度很快。

  2、靈活:HTTP允許傳輸任意類型的數據對象。正在傳輸的類型由Conten-Type加以標記。

  3、無連接:無連接的含義是限制每次連接只處理一個請求、服務器處理完客戶的請求,並收到客戶的應答後,即斷開連接。采用這種方式可以節省傳輸時間。

  4、無狀態:HTTP協議是無狀態協議。無狀態是指對於事務處理沒有記憶能力。

缺少狀態意味著若後續處理需要前面的信息,則它必須重傳,這樣可能導致每次連接傳送的數據量增大。另一方面,在服務器不需要先前信息時,它的應答就較快。

三、HTTP原理

  HTTP協議定義Web客戶端如何從Web服務器請求Web頁面,以及服務器如何把Web頁面傳送給客戶端。HTTP協議采用了請求/響應模型。客戶端向服務器發送一個請求報文,請求報文包含請求的方法、URL、協議版本、請求頭部和請求數據。服務器以一個狀態行作為響應,響應的內容包括協議的版本、成功或者錯誤代碼、服務器信息、響應頭部和響應數據。

  1、HTTP請求/響應的步驟

    1、客戶端連接到Web服務器

  一個HTTP客戶端,通常是瀏覽器,與Web服務器的HTTP端口(默認為80)建立一個TCP套接字連接。例如,http://www.oakcms.cn。

    2、發送HTTP請求

  通過TCP套接字,客戶端向Web服務器發送一個文本的請求報文,一個請求報文由請求行、請求頭部、空行和請求數據4部分組成。

    3、服務器接受請求並返回HTTP響應

  Web服務器解析請求,定位請求資源。服務器將資源復本寫到TCP套接字,由客戶端讀取。一個響應由狀態行、響應頭部、空行和響應數據4部分組成。

    4、釋放連接TCP連接

  若connection 模式為close,則服務器主動關閉TCP連接,客戶端被動關閉連接,釋放TCP連接;若connection 模式為keepalive,則該連接會保持一段時間,在該時間內可以繼續接收請求;

    5、客戶端瀏覽器解析HTML內容

  客戶端瀏覽器首先解析狀態行,查看表明請求是否成功的狀態代碼。然後解析每一個響應頭,響應頭告知以下為若幹字節的HTML文檔和文檔的字符集。客戶端瀏覽器讀取響應數據HTML,根據HTML的語法對其進行格式化,並在瀏覽器窗口中顯示。

  2、應用:在瀏覽器地址欄鍵入URL,按下回車之後會經歷以下流程:

    1、瀏覽器向 DNS 服務器請求解析該 URL 中的域名所對應的 IP 地址;

    2、解析出 IP 地址後,根據該 IP 地址和默認端口 80,和服務器建立TCP連接;

    3、瀏覽器發出讀取文件(URL 中域名後面部分對應的文件)的HTTP 請求,該請求報文作為 TCP 三次握手的第三個報文的數據發送給服務器;

    4、服務器對瀏覽器請求作出響應,並把對應的 html 文本發送給瀏覽器;

    5、釋放 TCP連接;

    6、瀏覽器將該 html 文本並顯示內容。

四、HTTP請求協議

  1、請求協議遵循的格式如下:

請求首行;        // 請求方式 請求路徑 協議和版本,例如:GET /index.html HTTP/1.1
請求頭信息;      // 請求頭名稱:請求頭內容,即為key:value格式,例如:Host:localhost
空行;           // 用來與請求體分隔開
請求體。         // GET沒有請求體,只有POST有請求體。

  瀏覽器發送給服務器的內容就這個格式的,如果不是這個格式服務器將無法解讀!

  2、請求方法  

  在HTTP協議中,請求有很多請求方法,其中最為常用的就是GETPOST

    1、get請求
GET /562f25980001b1b106000338.jpg HTTP/1.1
Host    img.mukewang.com
User-Agent    Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36
Accept    image/webp,image/*,*/*;q=0.8
Referer    http://www.imooc.com/
Accept-Encoding    gzip, deflate, sdch
Accept-Language    zh-CN,zh;q=0.8

HTTP默認的請求方法就是GET
* 沒有請求體
* 數據量有限制!
* GET請求數據會暴露在瀏覽器的地址欄中

GET請求常用的操作:
1. 在瀏覽器的地址欄中直接給出URL,那麽就一定是GET請求
2. 點擊頁面上的超鏈接也一定是GET請求
3. 提交表單時,表單默認使用GET請求,但可以設置為POST

請求頭:  

1、Host

請求的web服務器域名地址

2、User-Agent

HTTP客戶端運行的瀏覽器類型的詳細信息。通過該頭部信息,web服務器可以判斷出http請求的客戶端的瀏覽器的類型。

3、Accept

指定客戶端能夠接收的內容類型,內容類型的先後次序表示客戶都接收的先後次序

4、Accept-Lanuage

指定HTTP客戶端瀏覽器用來展示返回信息優先選擇的語言

5、Accept-Encoding

指定客戶端瀏覽器可以支持的web服務器返回內容壓縮編碼類型。表示允許服務器在將輸出內容發送到客戶端以前進行壓縮,以節約帶寬。
而這裏設置的就是客戶端瀏覽器所能夠支持的返回壓縮格式。

6、Accept-Charset

HTTP客戶端瀏覽器可以接受的字符編碼集

7、Content-Type

顯示此HTTP請求提交的內容類型。一般只有post提交時才需要設置該屬性

有關Content-Type屬性值有如下兩種編碼類型:

(1)“application/x-www-form-urlencoded”: 表單數據向服務器提交時所采用的編碼類型,默認的缺省值就是“application/x-www-form-urlencoded”。
     然而,在向服務器發送大量的文本、包含非ASCII字符的文本或二進制數據時這種編碼方式效率很低。

(2)“multipart/form-data”: 在文件上載時,所使用的編碼類型應當是“multipart/form-data”,它既可以發送文本數據,也支持二進制數據上載。

當提交為表單數據時,可以使用“application/x-www-form-urlencoded”;當提交的是文件時,就需要使用“multipart/form-data”編碼類型。
    2、post請求
POST / HTTP1.1
Host:www.wrox.com
User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Content-Type:application/x-www-form-urlencoded
Content-Length:40
Connection: Keep-Alive

name=Professional%20Ajax&publisher=Wiley

五、HTTP響應協議

  1、響應格式

  一般情況下,服務器接收並處理客戶端發過來的請求後會返回一個HTTP的響應消息。

  HTTP響應也由四個部分組成,分別是:狀態行、消息報頭、空行和響應正文。

  技術分享圖片

  2、範例

HTTP/1.1 200 OK
Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8

<html>
      <head></head>
      <body>
            <!--body goes here-->
      </body>
</html>
  第一部分:狀態行,由HTTP協議版本號, 狀態碼, 狀態消息 三部分組成。

  第一行為狀態行,(HTTP/1.1)表明HTTP版本為1.1版本,狀態碼為200,狀態消息為(ok)

  第二部分:消息報頭,用來說明客戶端要使用的一些附加信息

  第二行和第三行為消息報頭,
  Date:生成響應的日期和時間;Content-Type:指定了MIME類型的HTML(text/html),編碼類型是UTF-8

  第三部分:空行,消息報頭後面的空行是必須的
  第四部分:響應正文,服務器返回給客戶端的文本信息。

  空行後面的html部分為響應正文。

  3、響應狀態碼

  狀態碼分類:

狀態代碼有三位數字組成,第一個數字定義了響應的類別,共分五種類別:
1xx:指示信息--表示請求已接收,繼續處理
2xx:成功--表示請求已被成功接收、理解、接受
3xx:重定向--要完成請求必須進行更進一步的操作
4xx:客戶端錯誤--請求有語法錯誤或請求無法實現
5xx:服務器端錯誤--服務器未能實現合法的請求

  常見狀態碼:

200 OK                        //客戶端請求成功
400 Bad Request               //客戶端請求有語法錯誤,不能被服務器所理解
401 Unauthorized              //請求未經授權,這個狀態代碼必須和WWW-Authenticate報頭域一起使用 
403 Forbidden                 //服務器收到請求,但是拒絕提供服務
404 Not Found                 //請求資源不存在,eg:輸入了錯誤的URL
500 Internal Server Error     //服務器發生不可預期的錯誤
503 Server Unavailable        //服務器當前不能處理客戶端的請求,一段時間後可能恢復正

  更多的狀態碼鏈接:http://www.runoob.com/http/http-status-codes.html

  4、GET與POST請求的區別

  GET請求:註意最後一行是空行

GET /books/?sex=man&name=Professional HTTP/1.1
Host: www.wrox.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Connection: Keep-Alive

  POST

POST / HTTP/1.1
Host: www.wrox.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: Keep-Alive

name=Professional%20Ajax&publisher=Wiley

  1、GET提交,請求的數據會附在URL之後(就是把數據放置在HTTP協議頭中),以?分割URL和傳輸數據,多個參數用&連接;例 如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0 %E5%A5%BD。如果數據是英文字母/數字,原樣發送,如果是空格,轉換為+,如果是中文/其他字符,則直接把字符串用BASE64加密,得出如: %E4%BD%A0%E5%A5%BD,其中%XX中的XX為該符號以16進制表示的ASCII。

  POST提交:把提交的數據放置在是HTTP包的包體中。上文示例中紅色字體標明的就是實際的傳輸數據

因此,GET提交的數據會在地址欄中顯示出來,而POST提交,地址欄不會改變。

  2、傳輸數據的大小:首先聲明:HTTP協議沒有對傳輸的數據大小進行限制,HTTP協議規範也沒有對URL長度進行限制。

  而在實際開發中存在的限制主要有:

GET:特定瀏覽器和服務器對URL長度有限制,例如 IE對URL長度的限制是2083字節(2K+35)。對於其他瀏覽器,如Netscape、FireFox等,理論上沒有長度限制,其限制取決於操作系 統的支持。

因此對於GET提交時,傳輸數據就會受到URL長度的 限制。

POST:由於不是通過URL傳值,理論上數據不受 限。但實際各個WEB服務器會規定對post提交數據大小進行限制,Apache、IIS6都有各自的配置。

  GET和POST的區別
  1. GET提交的數據會放在URL之後,以?分割URL和傳輸數據,參數之間以&相連,如EditPosts.aspx?name=test1&id=123456. POST方法是把提交的數據放在HTTP包的Body中.
  2. GET提交的數據大小有限制(因為瀏覽器對URL的長度有限制),而POST方法提交的數據沒有限制.
  3. GET方式需要使用Request.QueryString來取得變量的值,而POST方式通過Request.Form來獲取變量的值。
  4. GET方式提交數據,會帶來安全問題,比如一個登錄頁面,通過GET方式提交數據時,用戶名和密碼將出現在URL上,如果頁面可以被緩存或者其他人可以訪問這臺機器,就可以從歷史記錄獲得該用戶的賬號和密碼.

二、WEB應用和WEB框架

一、WEB應用

  對於所有的web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端。

import socket

def handle_request(client):

    buf = client.recv(1024)
    client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8"))
    client.send("<h1 style=‘color:red‘>Hello, yuan</h1>".encode("utf8"))

def main():

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((localhost,8001))
    sock.listen(5)

    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()

if __name__ == __main__:

    main()

  最簡單的web應用就是HTML用文件保存好,用一個線程的HTTP服務器軟件,接收用戶請求,從文件中讀取HTML,返回。

  若要動態生成HTML,就需要把上述步驟自己來實現。不過,接收HTTP請求、解析。HTTP請求、發送HTTP響應都是苦力活,若自己來寫這些底層代碼,還沒開始寫動態HTML呢,就的花個月去讀HTTP規範。

  正確的做法是底層代碼由專門的服務器軟件實現,我們用Python專註於生成HTML文檔。因為我們不希望接觸到TCP連接、HTTP原始請求和響應格式,所以,需要一個統一的接口,讓我們專心用Python編寫Web業務。

  這個接口就是WSGI:Web Server Gateway Interface。

二、wsgiref模塊

from wsgiref.simple_server import make_server


def application(environ, start_response):
    start_response(200 OK, [(Content-Type, text/html)])
    return [b<h1>Hello, web!</h1>]


httpd = make_server(‘‘, 8080, application)

print(Serving HTTP on port 8000...)
# 開始監聽HTTP請求:
httpd.serve_forever()

三、web框架

  manage.py

from wsgiref.simple_server import make_server

#  request            response


from app01.views import *

from app01 import urls


def routers():

    URLpattern=urls.URLpattern

    return URLpattern


def applications(environ,start_response):

    path=environ.get("PATH_INFO")
    print("path",path)
    start_response(200 OK, [(Content-Type, text/html),(Charset, utf8)])

    urlpattern=routers()
    func=None

    for item in urlpattern:
        if path==item[0]:
            func=item[1]
            break

    if func:
        return [func(environ)]
    else:
        return [b"<h1>404!<h1>"]


    # return [b"<h1>hello world<h1>"]


if __name__ == __main__:

    t=make_server("",8810,applications)
    print("server is working...")
    t.serve_forever()

HTTP協議和WEB框架