关于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. 基于tcp/ip協議2. 基于請求,響應模式
3. 無狀態保存(**************)
4. 無連接(連接之后斷開,其實有短暫停留監聽客戶端是否有后續的操作)
?
http協議格式
請求首行; // 請求方式 請求路徑 協議和版本,例如:GET /index.html HTTP/1.1 請求頭信息; // 請求頭名稱:請求頭內容,即為key:value格式,例如:Host:localhost 空行; // 用來與請求體分隔開 請求體。 // GET沒有請求體,只有POST有請求體。?
請求協議:有兩種請求方式 get post關于get
"GET 路徑?user=yuan&pwd=123 HTTP/1.1 # 請求首行 ? ?后面為用戶輸入的參數(請求數據)以鍵值對參數形成
user-agent: Windows NT Chrome, # 請求頭 ? ? ? ? ??
accept-encoding: gzip, deflate, # 請求頭
k1:v1,# 請求頭
空行
"
"POST 路徑?user=yuan&pwd=123 HTTP/1.1 ?# 請求首行
user-agent: Windows NT Chrome, ? ? # 請求頭
accept-encoding: gzip, deflate, ? # 請求頭
k1:v1, ? ? ? ? ? ? ? ? ? ? ? ? ? ?# 請求頭
空行
user=yuan&pwd=123 ? ? ?# 請求體:存放請求數據(只有POST請求才有請求體)
"
"HTTP/1.1 200 OK ? ? ? ? ? ? ? ? ? ? ?# 響應首行 ? HTTP/協議及版本 狀態碼
content-length: 29878, ? ? ? ? ? ? ? # 響應頭 ? ? ? ? ? ? ? ??
date: Fri, 28 Dec 2018 01:43:30 GMT ?# 響應頭
server: JDWS/2.0 ? ? ? ? ? ? ? ? ? ? # 響應頭
空行
響應體
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.8HTTP默認的請求方法就是GET
* 沒有請求體
* 數據量有限制!
* GET請求數據會暴露在瀏覽器的地址欄中
GET請求常用的操作:
1. 在瀏覽器的地址欄中直接給出URL,那么就一定是GET請求
2. 點擊頁面上的超鏈接也一定是GET請求
3. 提交表單時,表單默認使用GET請求,但可以設置為POST
請求頭:
1、Host請求的web服務器域名地址2、User-AgentHTTP客戶端運行的瀏覽器類型的詳細信息。通過該頭部信息,web服務器可以判斷出http請求的客戶端的瀏覽器的類型。3、Accept指定客戶端能夠接收的內容類型,內容類型的先后次序表示客戶都接收的先后次序4、Accept-Lanuage指定HTTP客戶端瀏覽器用來展示返回信息優先選擇的語言5、Accept-Encoding指定客戶端瀏覽器可以支持的web服務器返回內容壓縮編碼類型。表示允許服務器在將輸出內容發送到客戶端以前進行壓縮,以節約帶寬。 而這里設置的就是客戶端瀏覽器所能夠支持的返回壓縮格式。6、Accept-CharsetHTTP客戶端瀏覽器可以接受的字符編碼集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-Alivename=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-Alivename=Professional%20Ajax&publisher=Wiley1、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的區別
GET提交的數據會放在URL之后,以?分割URL和傳輸數據,參數之間以&相連,如EditPosts.aspx?name=test1&id=123456. POST方法是把提交的數據放在HTTP包的Body中.
GET提交的數據大小有限制(因為瀏覽器對URL的長度有限制),而POST方法提交的數據沒有限制.
GET方式需要使用Request.QueryString來取得變量的值,而POST方式通過Request.Form來獲取變量的值。
GET方式提交數據,會帶來安全問題,比如一個登錄頁面,通過GET方式提交數據時,用戶名和密碼將出現在URL上,如果頁面可以被緩存或者其他人可以訪問這臺機器,就可以從歷史記錄獲得該用戶的賬號和密碼.
web應用與web框架
web應用
對于所有的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端。
import socketdef 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_serverdef 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 responsefrom app01.views import *from app01 import urlsdef routers():URLpattern=urls.URLpatternreturn URLpatterndef 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=Nonefor item in urlpattern:if path==item[0]:func=item[1]breakif 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 pymysqlfrom urllib.parse import parse_qsdef 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"))%userreturn data.encode("utf8")else:return b"user or pwd is wrong"else:f = open("templates/login.html", "rb")data = f.read()f.close()return datamodels
import pymysqlimport 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()?
轉載于:https://www.cnblogs.com/tjp40922/p/10192989.html
總結
- 上一篇: ubuntu12下subversion
- 下一篇: getopt实现传参自动识别