Python中的HTTP协议
生活随笔
收集整理的這篇文章主要介紹了
Python中的HTTP协议
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Python中的HTTP協(xié)議
文章目錄
- Python中的HTTP協(xié)議
- 一、HTTP詳解
- 二、http協(xié)議的格式
- 1、 HTTP請(qǐng)求
- 2.HTTP響應(yīng)
- 3.HTTP格式
- 三、例
- Web靜態(tài)服務(wù)器-1-顯示固定的頁(yè)面
- Web靜態(tài)服務(wù)器-2-顯示需要的頁(yè)面
- Web靜態(tài)服務(wù)器-3-多進(jìn)程
- Web靜態(tài)服務(wù)器-4-多線程
- Web靜態(tài)服務(wù)器-5-非堵塞模式
- 單進(jìn)程非堵塞 模型
- web靜態(tài)服務(wù)器-單進(jìn)程非堵塞
- Web靜態(tài)服務(wù)器-6-gevent版
一、HTTP詳解
HTTP詳解
二、http協(xié)議的格式
1、 HTTP請(qǐng)求
- 步驟1:瀏覽器首先向服務(wù)器發(fā)送HTTP請(qǐng)求,請(qǐng)求包括:
- 方法:GET還是POST,GET僅請(qǐng)求資源,POST會(huì)附帶用戶數(shù)據(jù);
- 路徑:/full/url/path;
- 域名:由Host頭指定:Host: www.sina.com
- 以及其他相關(guān)的Header;
- 如果是POST,那么請(qǐng)求還包括一個(gè)Body,包含用戶數(shù)據(jù)
2.HTTP響應(yīng)
- 步驟2:服務(wù)器向?yàn)g覽器返回HTTP響應(yīng),響應(yīng)包括:
- 響應(yīng)代碼:200表示成功,3xx表示重定向,4xx表示客戶端發(fā)送的請(qǐng)求有錯(cuò)誤,5xx表示服務(wù)器端處理時(shí)發(fā)生了錯(cuò)誤;
- 響應(yīng)類型:由Content-Type指定;
- 以及其他相關(guān)的Header;
- \r\n
- 通常服務(wù)器的HTTP響應(yīng)會(huì)攜帶內(nèi)容,也就是有一個(gè)Body,包含響應(yīng)的內(nèi)容,網(wǎng)頁(yè)的HTML源碼就在Body中。
- 步驟3:如果瀏覽器還需要繼續(xù)向服務(wù)器請(qǐng)求其他資源,比如圖片,就再次發(fā)出HTTP請(qǐng)求,重復(fù)步驟1、2。
3.HTTP格式
每個(gè)HTTP請(qǐng)求和響應(yīng)都遵循相同的格式,一個(gè)HTTP包含Header和Body兩部分,其中Body是可選的。
HTTP協(xié)議是一種文本協(xié)議,所以,它的格式也非常簡(jiǎn)單。
- 3.1 HTTP GET請(qǐng)求的格式:
每個(gè)Header一行一個(gè),換行符是\r\n。
- 3.2 HTTP POST請(qǐng)求的格式:
當(dāng)遇到連續(xù)兩個(gè)\r\n時(shí),Header部分結(jié)束,后面的數(shù)據(jù)全部是Body。
- 3.3 HTTP響應(yīng)的格式:
HTTP響應(yīng)如果包含body,也是通過\r\n\r\n來分隔的。
三、例
Web靜態(tài)服務(wù)器-1-顯示固定的頁(yè)面
#coding=utf-8 import socketdef handle_client(client_socket):"為一個(gè)客戶端進(jìn)行服務(wù)"recv_data = client_socket.recv(1024).decode("utf-8")request_header_lines = recv_data.splitlines()for line in request_header_lines:print(line)# 組織相應(yīng) 頭信息(header)response_headers = "HTTP/1.1 200 OK\r\n" # 200表示找到這個(gè)資源response_headers += "\r\n" # 用一個(gè)空的行與body進(jìn)行隔開# 組織 內(nèi)容(body)response_body = "hello world"response = response_headers + response_bodyclient_socket.send(response.encode("utf-8"))client_socket.close()def main():"作為程序的主控制入口"server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 設(shè)置當(dāng)服務(wù)器先close 即服務(wù)器端4次揮手之后資源能夠立即釋放,這樣就保證了,下次運(yùn)行程序時(shí) 可以立即綁定7788端口server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)server_socket.bind(("", 7788))server_socket.listen(128)while True:client_socket, client_addr = server_socket.accept()handle_client(client_socket)if __name__ == "__main__":main()Web靜態(tài)服務(wù)器-2-顯示需要的頁(yè)面
#coding=utf-8 import socket import redef handle_client(client_socket):"為一個(gè)客戶端進(jìn)行服務(wù)"recv_data = client_socket.recv(1024).decode('utf-8', errors="ignore")request_header_lines = recv_data.splitlines()for line in request_header_lines:print(line)http_request_line = request_header_lines[0]get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)print("file name is ===>%s" % get_file_name) # for test# 如果沒有指定訪問哪個(gè)頁(yè)面。例如index.html# GET / HTTP/1.1if get_file_name == "/":get_file_name = DOCUMENTS_ROOT + "/index.html"else:get_file_name = DOCUMENTS_ROOT + get_file_nameprint("file name is ===2>%s" % get_file_name) #for testtry:f = open(get_file_name, "rb")except IOError:# 404表示沒有這個(gè)頁(yè)面response_headers = "HTTP/1.1 404 not found\r\n"response_headers += "\r\n"response_body = "====sorry ,file not found===="else:response_headers = "HTTP/1.1 200 OK\r\n"response_headers += "\r\n"response_body = f.read()f.close()finally:# 因?yàn)轭^信息在組織的時(shí)候,是按照字符串組織的,不能與以二進(jìn)制打開文件讀取的數(shù)據(jù)合并,因此分開發(fā)送# 先發(fā)送response的頭信息client_socket.send(response_headers.encode('utf-8'))# 再發(fā)送bodyclient_socket.send(response_body)client_socket.close()def main():"作為程序的主控制入口"server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)server_socket.bind(("", 7788))server_socket.listen(128)while True:client_socket, clien_cAddr = server_socket.accept()handle_client(client_socket)#這里配置服務(wù)器 DOCUMENTS_ROOT = "./html"if __name__ == "__main__":main()Web靜態(tài)服務(wù)器-3-多進(jìn)程
#coding=utf-8 import socket import re import multiprocessingclass WSGIServer(object):def __init__(self, server_address):# 創(chuàng)建一個(gè)tcp套接字self.listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 允許立即使用上次綁定的portself.listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 綁定self.listen_socket.bind(server_address)# 變?yōu)楸粍?dòng),并制定隊(duì)列的長(zhǎng)度self.listen_socket.listen(128)def serve_forever(self):"循環(huán)運(yùn)行web服務(wù)器,等待客戶端的鏈接并為客戶端服務(wù)"while True:# 等待新客戶端到來client_socket, client_address = self.listen_socket.accept()print(client_address) # for testnew_process = multiprocessing.Process(target=self.handleRequest, args=(client_socket,))new_process.start()# 因?yàn)樽舆M(jìn)程已經(jīng)復(fù)制了父進(jìn)程的套接字等資源,所以父進(jìn)程調(diào)用close不會(huì)將他們對(duì)應(yīng)的這個(gè)鏈接關(guān)閉的client_socket.close()def handleRequest(self, client_socket):"用一個(gè)新的進(jìn)程,為一個(gè)客戶端進(jìn)行服務(wù)"recv_data = client_socket.recv(1024).decode('utf-8')print(recv_data)requestHeaderLines = recv_data.splitlines()for line in requestHeaderLines:print(line)request_line = requestHeaderLines[0]get_file_name = re.match("[^/]+(/[^ ]*)", request_line).group(1)print("file name is ===>%s" % get_file_name) # for testif get_file_name == "/":get_file_name = DOCUMENTS_ROOT + "/index.html"else:get_file_name = DOCUMENTS_ROOT + get_file_nameprint("file name is ===2>%s" % get_file_name) # for testtry:f = open(get_file_name, "rb")except IOError:response_header = "HTTP/1.1 404 not found\r\n"response_header += "\r\n"response_body = "====sorry ,file not found===="else:response_header = "HTTP/1.1 200 OK\r\n"response_header += "\r\n"response_body = f.read()f.close()finally:client_socket.send(response_header.encode('utf-8'))client_socket.send(response_body)client_socket.close()# 設(shè)定服務(wù)器的端口 SERVER_ADDR = (HOST, PORT) = "", 8888 # 設(shè)置服務(wù)器服務(wù)靜態(tài)資源時(shí)的路徑 DOCUMENTS_ROOT = "./html"def main():httpd = WSGIServer(SERVER_ADDR)print("web Server: Serving HTTP on port %d ...\n" % PORT)httpd.serve_forever()if __name__ == "__main__":main()Web靜態(tài)服務(wù)器-4-多線程
#coding=utf-8 import socket import re import threadingclass WSGIServer(object):def __init__(self, server_address):# 創(chuàng)建一個(gè)tcp套接字self.listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 允許立即使用上次綁定的portself.listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 綁定self.listen_socket.bind(server_address)# 變?yōu)楸粍?dòng),并制定隊(duì)列的長(zhǎng)度self.listen_socket.listen(128)def serve_forever(self):"循環(huán)運(yùn)行web服務(wù)器,等待客戶端的鏈接并為客戶端服務(wù)"while True:# 等待新客戶端到來client_socket, client_address = self.listen_socket.accept()print(client_address)new_process = threading.Thread(target=self.handleRequest, args=(client_socket,))new_process.start()# 因?yàn)榫€程是共享同一個(gè)套接字,所以主線程不能關(guān)閉,否則子線程就不能再使用這個(gè)套接字了# client_socket.close() def handleRequest(self, client_socket):"用一個(gè)新的進(jìn)程,為一個(gè)客戶端進(jìn)行服務(wù)"recv_data = client_socket.recv(1024).decode('utf-8')print(recv_data)requestHeaderLines = recv_data.splitlines()for line in requestHeaderLines:print(line)request_line = requestHeaderLines[0]get_file_name = re.match("[^/]+(/[^ ]*)", request_line).group(1)print("file name is ===>%s" % get_file_name) # for testif get_file_name == "/":get_file_name = DOCUMENTS_ROOT + "/index.html"else:get_file_name = DOCUMENTS_ROOT + get_file_nameprint("file name is ===2>%s" % get_file_name) # for testtry:f = open(get_file_name, "rb")except IOError:response_header = "HTTP/1.1 404 not found\r\n"response_header += "\r\n"response_body = "====sorry ,file not found===="else:response_header = "HTTP/1.1 200 OK\r\n"response_header += "\r\n"response_body = f.read()f.close()finally:client_socket.send(response_header.encode('utf-8'))client_socket.send(response_body)client_socket.close()# 設(shè)定服務(wù)器的端口 SERVER_ADDR = (HOST, PORT) = "", 8888 # 設(shè)置服務(wù)器服務(wù)靜態(tài)資源時(shí)的路徑 DOCUMENTS_ROOT = "./html"def main():httpd = WSGIServer(SERVER_ADDR)print("web Server: Serving HTTP on port %d ...\n" % PORT)httpd.serve_forever()if __name__ == "__main__":main()Web靜態(tài)服務(wù)器-5-非堵塞模式
單進(jìn)程非堵塞 模型
#coding=utf-8 from socket import * import time# 用來存儲(chǔ)所有的新鏈接的socket g_socket_list = list()def main():server_socket = socket(AF_INET, SOCK_STREAM)server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR , 1)server_socket.bind(('', 7890))server_socket.listen(128)# 將套接字設(shè)置為非堵塞# 設(shè)置為非堵塞后,如果accept時(shí),恰巧沒有客戶端connect,那么accept會(huì)# 產(chǎn)生一個(gè)異常,所以需要try來進(jìn)行處理server_socket.setblocking(False)while True:# 用來測(cè)試time.sleep(0.5)try:newClientInfo = server_socket.accept()except Exception as result:passelse:print("一個(gè)新的客戶端到來:%s" % str(newClientInfo))newClientInfo[0].setblocking(False) # 設(shè)置為非堵塞g_socket_list.append(newClientInfo)for client_socket, client_addr in g_socket_list:try:recvData = client_socket.recv(1024)if recvData:print('recv[%s]:%s' % (str(client_addr), recvData))else:print('[%s]客戶端已經(jīng)關(guān)閉' % str(client_addr))client_socket.close()g_socket_list.remove((client_socket,client_addr))except Exception as result:passprint(g_socket_list) # for testif __name__ == '__main__':main()web靜態(tài)服務(wù)器-單進(jìn)程非堵塞
import time import socket import sys import reclass WSGIServer(object):"""定義一個(gè)WSGI服務(wù)器的類"""def __init__(self, port, documents_root):# 1. 創(chuàng)建套接字self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 2. 綁定本地信息self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)self.server_socket.bind(("", port))# 3. 變?yōu)楸O(jiān)聽套接字self.server_socket.listen(128)self.server_socket.setblocking(False)self.client_socket_list = list()self.documents_root = documents_rootdef run_forever(self):"""運(yùn)行服務(wù)器"""# 等待對(duì)方鏈接while True:# time.sleep(0.5) # for testtry:new_socket, new_addr = self.server_socket.accept()except Exception as ret:print("-----1----", ret) # for testelse:new_socket.setblocking(False)self.client_socket_list.append(new_socket)for client_socket in self.client_socket_list:try:request = client_socket.recv(1024).decode('utf-8')except Exception as ret:print("------2----", ret) # for testelse:if request:self.deal_with_request(request, client_socket)else:client_socket.close()self.client_socket_list.remove(client_socket)print(self.client_socket_list)def deal_with_request(self, request, client_socket):"""為這個(gè)瀏覽器服務(wù)器"""if not request:returnrequest_lines = request.splitlines()for i, line in enumerate(request_lines):print(i, line)# 提取請(qǐng)求的文件(index.html)# GET /a/b/c/d/e/index.html HTTP/1.1ret = re.match(r"([^/]*)([^ ]+)", request_lines[0])if ret:print("正則提取數(shù)據(jù):", ret.group(1))print("正則提取數(shù)據(jù):", ret.group(2))file_name = ret.group(2)if file_name == "/":file_name = "/index.html"# 讀取文件數(shù)據(jù)try:f = open(self.documents_root+file_name, "rb")except:response_body = "file not found, 請(qǐng)輸入正確的url"response_header = "HTTP/1.1 404 not found\r\n"response_header += "Content-Type: text/html; charset=utf-8\r\n"response_header += "Content-Length: %d\r\n" % (len(response_body))response_header += "\r\n"# 將header返回給瀏覽器client_socket.send(response_header.encode('utf-8'))# 將body返回給瀏覽器client_socket.send(response_body.encode("utf-8"))else:content = f.read()f.close()response_body = contentresponse_header = "HTTP/1.1 200 OK\r\n"response_header += "Content-Length: %d\r\n" % (len(response_body))response_header += "\r\n"# 將header返回給瀏覽器client_socket.send( response_header.encode('utf-8') + response_body)# 設(shè)置服務(wù)器服務(wù)靜態(tài)資源時(shí)的路徑 DOCUMENTS_ROOT = "./html"def main():"""控制web服務(wù)器整體"""# python3 xxxx.py 7890if len(sys.argv) == 2:port = sys.argv[1]if port.isdigit():port = int(port)else:print("運(yùn)行方式如: python3 xxx.py 7890")returnprint("http服務(wù)器使用的port:%s" % port)http_server = WSGIServer(port, DOCUMENTS_ROOT)http_server.run_forever()if __name__ == "__main__":main()Web靜態(tài)服務(wù)器-6-gevent版
from gevent import monkey import gevent import socket import sys import remonkey.patch_all()class WSGIServer(object):"""定義一個(gè)WSGI服務(wù)器的類"""def __init__(self, port, documents_root):# 1. 創(chuàng)建套接字self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 2. 綁定本地信息self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)self.server_socket.bind(("", port))# 3. 變?yōu)楸O(jiān)聽套接字self.server_socket.listen(128)self.documents_root = documents_rootdef run_forever(self):"""運(yùn)行服務(wù)器"""# 等待對(duì)方鏈接while True:new_socket, new_addr = self.server_socket.accept()gevent.spawn(self.deal_with_request, new_socket) # 創(chuàng)建一個(gè)協(xié)程準(zhǔn)備運(yùn)行它def deal_with_request(self, client_socket):"""為這個(gè)瀏覽器服務(wù)器"""while True:# 接收數(shù)據(jù)request = client_socket.recv(1024).decode('utf-8')# print(gevent.getcurrent())# print(request)# 當(dāng)瀏覽器接收完數(shù)據(jù)后,會(huì)自動(dòng)調(diào)用close進(jìn)行關(guān)閉,因此當(dāng)其關(guān)閉時(shí),web也要關(guān)閉這個(gè)套接字if not request:new_socket.close()breakrequest_lines = request.splitlines()for i, line in enumerate(request_lines):print(i, line)# 提取請(qǐng)求的文件(index.html)# GET /a/b/c/d/e/index.html HTTP/1.1ret = re.match(r"([^/]*)([^ ]+)", request_lines[0])if ret:print("正則提取數(shù)據(jù):", ret.group(1))print("正則提取數(shù)據(jù):", ret.group(2))file_name = ret.group(2)if file_name == "/":file_name = "/index.html"file_path_name = self.documents_root + file_nametry:f = open(file_path_name, "rb")except:# 如果不能打開這個(gè)文件,那么意味著沒有這個(gè)資源,沒有資源 那么也得需要告訴瀏覽器 一些數(shù)據(jù)才行# 404response_body = "沒有你需要的文件......".encode("utf-8")response_headers = "HTTP/1.1 404 not found\r\n"response_headers += "Content-Type:text/html;charset=utf-8\r\n"response_headers += "Content-Length:%d\r\n" % len(response_body)response_headers += "\r\n"send_data = response_headers.encode("utf-8") + response_bodyclient_socket.send(send_data)else:content = f.read()f.close()# 響應(yīng)的body信息response_body = content# 響應(yīng)頭信息response_headers = "HTTP/1.1 200 OK\r\n"response_headers += "Content-Type:text/html;charset=utf-8\r\n"response_headers += "Content-Length:%d\r\n" % len(response_body)response_headers += "\r\n"send_data = response_headers.encode("utf-8") + response_bodyclient_socket.send(send_data)# 設(shè)置服務(wù)器服務(wù)靜態(tài)資源時(shí)的路徑 DOCUMENTS_ROOT = "./html"def main():"""控制web服務(wù)器整體"""# python3 xxxx.py 7890if len(sys.argv) == 2:port = sys.argv[1]if port.isdigit():port = int(port)else:print("運(yùn)行方式如: python3 xxx.py 7890")returnprint("http服務(wù)器使用的port:%s" % port)http_server = WSGIServer(port, DOCUMENTS_ROOT")http_server.run_forever()if __name__ == "__main__":main()總結(jié)
以上是生活随笔為你收集整理的Python中的HTTP协议的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python中的网络编程之TCP
- 下一篇: Python中的select、epoll