淺析HTTP中POST和GET區別並用Python模擬其響應和請求
最近在幾周在做手遊崩潰資訊收集和上傳,拿到崩潰資訊後,使用的是HTTP的POST方法上傳到公司共用的伺服器的,因此做簡單總結。本文首先簡單介紹了HTTP協議,主要說明了POST方法和GET方法的區別;然後用Python實現了 對POST方法和GET方法的響應;最後用Python模擬了POST方法和GET方法的請求。
HTTP協議簡介
HTTP是Hyper Text Transfer Protocol(超文字傳輸協議)的縮寫,簡單來說它是一個應用層的協議,它允許將超文字標記語言(HTML)文件從Web伺服器傳送到客戶端的瀏覽器。HTTP是一個無狀態的協議,即同一個客戶端的這次請求和上次請求是沒有對應關係,對http伺服器來說,它並不知道這兩個請求來自同一個客戶端,為了解決這個問題,Web程式引入了Cookie機制來維護狀態。
HTTP協議通常基於TCP協議來實現的,有時也基於於TLS或SSL協議(這個兩個協議也是基於TCP協議來說實現)來實現,這個時候,就成了我們常說的HTTPS,每次HTTP操作都至少有下面幾個過程:首先客戶端與服務端建立連線;建立建立後,客戶端按照協議格式傳送請求;服務端接到請求後,同樣按照某個格式返回響應資料;最後客戶端與服務端斷開連線。
通常我們開啟一個網頁,需要瀏覽器傳送多次請求,因為一個網頁中可能引用了其他檔案,比如圖片等檔案,這時候瀏覽器會自動再次傳送請求去獲取圖片等資料,直到網頁上的資料被完全顯示出來。
POST和GET區別
HTTP協議定義了很多與伺服器互動的方法,最基本的有4種,分別是GET,POST,PUT,DELETE. 一個URL地址用於描述一個網路上的資源,而HTTP中的GET, POST, PUT, DELETE就對應著對這個資源的查,改,增,刪4個操作,其中最常見請求方式是GET和POST,並且現在瀏覽器一般只支援GET和POST方法。GET一般用於獲取/查詢資源資訊,而POST一般用於更新資源資訊,他們之間主要區別如下:
1)根據HTTP規範,GET用於資訊獲取,而且應該是安全的和冪等的,這裡安全是指該操作用於獲取資訊而非修改資訊,冪等是指對同一URL的多個請求應該返回同樣的結果(這一點在實質實現時,可能並不滿足);
POST表示可能修改變伺服器上的資源的請求。
2)GET請求的資料會附在URL之後(就是把資料放置在HTTP協議頭中),以?分割URL和傳輸資料,引數之間以&相連,如果資料是英文字母/數字,原樣傳送,如果是空格,轉換為+,如果是中文/其他字元,
則直接把字串用BASE64編碼;POST把提交的資料則放置在是HTTP包的包體中。
3)因為GET是通過URL提交資料,那麼GET可提交的資料量就跟URL的長度有直接關係,理論上URL長度是沒有限制的,即HTTP協議沒有規定URL的長度,但在實質中,特定的瀏覽器可能對這個長度做了限制;理論上POST也是沒有大小限制的,HTTP協議規範也沒有進行大小限制,但在服務端通常會對這個大小做一個限制,當然這個限制比GET寬鬆的多,即使用POST可以提交的資料量比GET大得多。
最後,網上有人說,POST的安全性要比GET的安全性高,實質上POST跟GET都是明文傳輸,這可以通過類似WireShark工具看到。總之,Get是向伺服器發索取資料的一種請求,而Post是向伺服器提交資料的一種請求。
POST和GET方法響應Python實現
下面程式碼實現對POST方法和GET方法的響應:
對於上面POST響應實現,值得一提的是,若客戶端傳送過來一個檔案,則方法getvalue()會把整個檔案內容讀入記憶體,這可能不是我們想要的,這時可以使用form的屬性file或filename,比如下面程式碼,計算上傳程式碼的行數:#!/usr/bin/python #coding=utf8 """ import sys reload(sys) sys.setdefaultencoding('utf-8') """ from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer from os import curdir, sep import cgi import logging import time PORT_NUMBER = 8080 RES_FILE_DIR = "." class myHandler(BaseHTTPRequestHandler): def do_GET(self): if self.path=="/": self.path="/index_example3.html" try: #根據請求的副檔名,設定正確的mime型別 sendReply = False if self.path.endswith(".html"): mimetype='text/html' sendReply = True if self.path.endswith(".jpg"): mimetype='image/jpg' sendReply = True if self.path.endswith(".gif"): mimetype='image/gif' sendReply = True if self.path.endswith(".js"): mimetype='application/javascript' sendReply = True if self.path.endswith(".css"): mimetype='text/css' sendReply = True if sendReply == True: #讀取相應的靜態資原始檔,併發送它 f = open(curdir + sep + self.path, 'rb') self.send_response(200) self.send_header('Content-type',mimetype) self.end_headers() self.wfile.write(f.read()) f.close() return except IOError: self.send_error(404,'File Not Found: %s' % self.path) def do_POST(self): logging.warning(self.headers) form = cgi.FieldStorage( fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE':self.headers['Content-Type'], }) file_name = self.get_data_string() path_name = '%s/%s.log' % (RES_FILE_DIR,file_name) fwrite = open(path_name,'a') fwrite.write("name=%s\n" % form.getvalue("name","")) fwrite.write("addr=%s\n" % form.getvalue("addr","")) fwrite.close() self.send_response(200) self.end_headers() self.wfile.write("Thanks for you post") def get_data_string(self): now = time.time() clock_now = time.localtime(now) cur_time = list(clock_now) date_string = "%d-%d-%d-%d-%d-%d" % (cur_time[0], cur_time[1],cur_time[2],cur_time[3],cur_time[4],cur_time[5]) return date_string try: server = HTTPServer(('', PORT_NUMBER), myHandler) print 'Started httpserver on port ' , PORT_NUMBER server.serve_forever() except KeyboardInterrupt: print '^C received, shutting down the web server' server.socket.close()
fileitem = form["userfile"]
if fileitem.file:
linecount = 0
while 1:
line = fileitem.file.readline()
if not line: break
linecount = linecount + 1
POST和GET方法請求Python實現下面程式碼實現了GET方法的請求:
#!/usr/bin/env python
#coding=utf8
import httplib
httpClient = None
try:
httpClient = httplib.HTTPConnection('localhost', 8080, timeout=30)
httpClient.request('GET', '/test0.html')
#response是HTTPResponse物件
response = httpClient.getresponse()
print response.status
print response.reason
print response.read()
except Exception, e:
print e
finally:
if httpClient:
httpClient.close()
下面程式碼實現了POST方法的請求:#!/usr/bin/env python
#coding=utf8
import httplib, urllib
httpClient = None
try:
params = urllib.urlencode({'name': 'Maximus', 'addr': "GZ"})
headers = {"Content-type": "application/x-www-form-urlencoded"
, "Accept": "text/plain"}
httpClient = httplib.HTTPConnection("localhost", 8080, timeout=30)
httpClient.request("POST", "/test0.html", params, headers)
response = httpClient.getresponse()
print response.status
print response.reason
print response.read()
print response.getheaders() #獲取頭資訊
except Exception, e:
print e
finally:
if httpClient:
httpClient.close()
參考資料
http://www.cnblogs.com/TankXiao/archive/2012/02/13/2342672.html
http://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html
http://www.acmesystems.it/python_httpserver
http://georgik.sinusgear.com/2011/01/07/how-to-dump-post-request-with-python/
http://www.01happy.com/python-httplib-get-and-post/