1. 程式人生 > >自定義Web框架 自定義Web框架

自定義Web框架 自定義Web框架

自定義Web框架

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允許傳輸任意型別的資料物件。正在傳輸的型別由Content-Type加以標記。

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

4.無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味著如果後續處理需要前面的資訊,則它必須重傳,這樣可能導致每次連線傳送的資料量增大。另一方面,在伺服器不需要先前資訊時它的應答就較快。

 

HTTP請求協議

請求協議遵照以下格式:

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

瀏覽器傳送給伺服器的內容就這個格式的,如果不是這個格式伺服器將無法解讀!在HTTP協議中,請求有很多請求方法,其中最為常用的就是GETPOST

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”編碼型別。 8、Keep-Alive 表示是否需要持久連線。如果web伺服器端看到這裡的值為“Keep-Alive”,或者看到請求使用的是HTTP 1.1(HTTP 1.1預設進行持久連線),它就可以利用持久連線的優點
複製程式碼 複製程式碼

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
複製程式碼 複製程式碼

第一部分:請求行,第一行明瞭是post請求,以及http1.1版本。
第二部分:請求頭部,第二行至第六行。
第三部分:空行,第七行的空行。
第四部分:請求資料,第八行。

HTTP響應協議

 響應格式

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

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

http響應訊息格式.jpg

例子

 
       
       
        複製程式碼
        
       
        複製程式碼
        
       
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部分為響應正文。

響應狀態碼

 

複製程式碼 複製程式碼
狀態程式碼有三位數字組成,第一個數字定義了響應的類別,共分五種類別:
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        //伺服器當前不能處理客戶端的請求,一段時間後可能恢復正常
複製程式碼 複製程式碼

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()
複製程式碼 複製程式碼

DIY一個自己的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()
複製程式碼 複製程式碼

urls

from app01.views import *


URLpattern = (
    ("/login/", login),
)

views

複製程式碼 複製程式碼
import pymysql

from urllib.parse import parse_qs


def login(request):

    if request.get("REQUEST_METHOD")=="POST":
        print("+++++",request)


        #當請求方式是GET時
        # user_union,pwd_union=request.get("QUERY_STRING").split("&")
        # _,user=user_union.split("=")
        # _,pwd=pwd_union.split("=")

        # 環境變數 CONTENT_LENGTH 可能是空值 或者 值丟失
        try:
            request_body_size = int(request.get('CONTENT_LENGTH', 0))
        except (ValueError):
            request_body_size = 0
        # 當請求方式是POST時, 變數將會被放在存在域wsgi.input檔案中的HTTP請求資訊中, 由WSGI 伺服器一起傳送.
        request_body = request['wsgi.input'].read(request_body_size)
        d = parse_qs(request_body)


        user=d.get(b"user")[0].decode("utf8")
        pwd=d.get(b"pwd")[0].decode("utf8")

        print("user",user,pwd)


        #連線資料庫
        conn = pymysql.connect(host='',port= 3306,user = 'root',passwd='',db='s6') #db:庫名
        #建立遊標
        cur = conn.cursor()

        SQL="select * from userinfo2 WHERE NAME ='%s' AND PASSWORD ='%s'"%(user,pwd)

        cur.execute(SQL)

        if cur.fetchone():

            f=open("templates/backend.html","rb")

            data=f.read()
            data=(data.decode("utf8"))%user
            return data.encode("utf8")

        else:
             return b"user or pwd is wrong"


    else:
        f = open("templates/login.html", "rb")

        data = f.read()
        f.close()

        return data
複製程式碼 複製程式碼

models

複製程式碼 複製程式碼
import pymysql


import pymysql
#連線資料庫
conn = pymysql.connect(host='',port= 3306,user = 'root',passwd='',db='s6') #db:庫名
#建立遊標
cur = conn.cursor()

# sql='''
# create table userinfo2(
#         id INT PRIMARY KEY ,
#         name VARCHAR(32) ,
#         password VARCHAR(32)
# )
#
# '''
#
# cur.execute(sql)
#
# cur.executemany("insert into userinfo2 values(%s,%s,%s)", [(1,"yuan","123"),
#                                                           (2,"alex","456"),
#                                                           (3,"egon","789")])


cur.execute("select * from userinfo2 WHERE NAME='yuan' AND PASSWORD ='123'")
#提交
conn.commit()
#關閉指標物件
cur.close()
#關閉連線物件
conn.close()
複製程式碼 複製程式碼

 

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允許傳輸任意型別的資料物件。正在傳輸的型別由Content-Type加以標記。

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

4.無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味著如果後續處理需要前面的資訊,則它必須重傳,這樣可能導致每次連線傳送的資料量增大。另一方面,在伺服器不需要先前資訊時它的應答就較快。

 

HTTP請求協議

請求協議遵照以下格式:

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

瀏覽器傳送給伺服器的內容就這個格式的,如果不是這個格式伺服器將無法解讀!在HTTP協議中,請求有很多請求方法,其中最為常用的就是GETPOST

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”編碼型別。 8、Keep-Alive 表示是否需要持久連線。如果web伺服器端看到這裡的值為“Keep-Alive”,或者看到請求使用的是HTTP 1.1(HTTP 1.1預設進行持久連線),它就可以利用持久連線的優點
複製程式碼 複製程式碼

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
複製程式碼 複製程式碼

第一部分:請求行,第一行明瞭是post請求,以及http1.1版本。
第二部分:請求頭部,第二行至第六行。
第三部分:空行,第七行的空行。
第四部分:請求資料,第八行。

HTTP響應協議

 響應格式

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

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

http響應訊息格式.jpg

例子

 
 
 
  複製程式碼
  
 
  複製程式碼
  
 
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部分為響應正文。

響應狀態碼

 

複製程式碼 複製程式碼
狀態程式碼有三位數字組成,第一個數字定義了響應的類別,共分五種類別:
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        //伺服器當前不能處理客戶端的請求,一段時間後可能恢復正常
複製程式碼 複製程式碼

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()
複製程式碼 複製程式碼

DIY一個自己的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()
複製程式碼 複製程式碼

urls

from app01.views import *


URLpattern = (
    ("/login/", login),
)

views

複製程式碼 複製程式碼
import pymysql

from urllib.parse import parse_qs


def login(request):

    if request.get("REQUEST_METHOD")=="POST":
        print("+++++",request)


        #當請求方式是GET時
        # user_union,pwd_union=request.get("QUERY_STRING").split("&")
        # _,user=user_union.split("=")
        # _,pwd=pwd_union.split("=")

        # 環境變數 CONTENT_LENGTH 可能是空值 或者 值丟失
        try:
            request_body_size = int(request.get('CONTENT_LENGTH', 0))
        except (ValueError):
            request_body_size = 0
        # 當請求方式是POST時, 變數將會被放在存在域wsgi.input檔案中的HTTP請求資訊中, 由WSGI 伺服器一起傳送.
        request_body = request['wsgi.input'].read(request_body_size)
        d = parse_qs(request_body)


        user=d.get(b"user")[0].decode("utf8")
        pwd=d.get(b"pwd")[0].decode("utf8")

        print("user",user,pwd)


        #連線資料庫
        conn = pymysql.connect(host='',port= 3306,user = 'root',passwd='',db='s6') #db:庫名
        #建立遊標
        cur = conn.cursor()

        SQL="select * from userinfo2 WHERE NAME ='%s' AND PASSWORD ='%s'"%(user,pwd)

        cur.execute(SQL)

        if cur.fetchone():

            f=open("templates/backend.html","rb")

            data=f.read()
            data=(data.decode("utf8"))%user
            return data.encode("utf8")

        else:
             return b"user or pwd is wrong"


    else:
        f = open("templates/login.html", "rb")

        data = f.read()
        f.close()

        return data
複製程式碼 複製程式碼

models

複製程式碼 複製程式碼
import pymysql


import pymysql
#連線資料庫
conn = pymysql.connect(host='',port= 3306,user = 'root',passwd='',db='s6') #db:庫名
#建立遊標
cur = conn.cursor()

# sql='''
# create table userinfo2(
#         id INT PRIMARY KEY ,
#         name VARCHAR(32) ,
#         password VARCHAR(32)
# )
#
# '''
#
# cur.execute(sql)
#
# cur.executemany("insert into userinfo2 values(%s,%s,%s)", [(1,"yuan","123"),
#                                                           (2,"alex","456"),
#                                                           (3,"egon","789")])


cur.execute("select * from userinfo2 WHERE NAME='yuan' AND PASSWORD ='123'")
#提交
conn.commit()
#關閉指標物件
cur.close()
#關閉連線物件
conn.close()
複製程式碼 複製程式碼