python搭建簡單的web伺服器

來源:互聯網
上載者:User

標籤:

由於要做自動化和效能測試,工作中需要有一個能夠控制返回訊息資料的web伺服器,所以用python初步實現了一個簡單的web伺服器,能夠處理HTTP的請求(GET,POST,PUT),並完成響應。
先簡單說明下原理,python中實現web伺服器大概分兩個步驟:

1.      建立一個通訊端,綁定到指定的IP和連接埠,保持監聽

2.      建立一個handle類,當收到請求訊息時,作出響應

主要使用的類有兩個:

HTTPServer:HTTP伺服器的基類,提供了HTTP伺服器的常用方法,建立伺服器時可以直接聲明這個類,也可以根據需要從這個類繼承。

CGIHTTPRequestHandler:處理請求的handle類,繼承自BaseHTTPRequestHandler類,在python文檔中說明該類可以處理GET和POST請求,自己試了一下發現也可以處理PUT請求。

有關這兩個類的詳細描述可以參考python的標準類庫說明:https://docs.python.org/2/library/

源碼如下:
import socket
from os import curdir,sep

from BaseHTTPServer import HTTPServer

from CGIHTTPServer import CGIHTTPRequestHandler

import json
class HttpHandler(CGIHTTPRequestHandler):

    def do_GET(self):

        try:

            f = open(curdir + sep + self.path)

            print self.path

            print ‘This is a GET method!‘

            self.send_response(200)

            self.send_header(‘Content-type‘,

                             ‘text/html‘)

            self.end_headers()

            self.wfile.write(f.read())

            f.close()

        except IOError:

            self.send_error(404,‘File Not Found:%s‘ % self.path)

    def do_POST(self):

        try:

            print self.path

            print ‘This is a POST method!‘

            self.data = self.request.recv(1024).strip()

            self.data =  json.loads(self.data)

            print self.data                       

            sendData = {}

            if self.path == ‘/getfile‘:

                f = open(curdir + sep + ‘/test_body.txt‘)

                fileContent = f.read()

                sendData[‘content‘] = fileContent

                f.close()

            self.send_response(200)

            self.send_header(‘Content-type‘,

                             ‘text/html‘)

            self.end_headers()

            self.wfile.write(sendData)

        except:

            self.send_error(404,‘Invalid request:%s!‘ % self.path)

    def do_PUT(self):

        try:

            print self.path

            print ‘This is a PUT method!‘

            self.data = self.request.recv(1024).strip()

            print self.data

            sendData = {}

            if self.path == ‘/getfile‘:

                f = open(curdir + sep + ‘/test_body.txt‘)

                fileContent = f.read()

                sendData[‘content‘] = fileContent

                f.close()

            self.send_response(200)

            self.send_header(‘Content-type‘,

                             ‘text/html‘)

            self.end_headers()

            self.wfile.write(sendData)

        except:

            self.send_error(404,‘Invalid request:%s!‘ % self.path)

       

def main():

    try:

         localIp = socket.gethostbyname(socket.gethostname())
        server_address = (localIp,8080)

        http_server = HTTPServer(server_address,HttpHandler)

        sa = http_server.socket.getsockname()

        print "Serving HTTP on", sa[0], "port", sa[1], "..."

        print ‘Press ^C once or twice to quit.‘

        http_server.serve_forever()

    except KeyboardInterrupt:

        print ‘^C received,shutting down server.‘

        http_server.socket.close()

       

if __name__ == ‘__main__‘:

main()      

在main()函數中建立了一個HTTPServer類,綁定到原生8080連接埠,並保持監聽。當收到請求時,根據請求的方法類型進入不同的do_*函數。函數的處理邏輯很簡單,如果發送的URL合法,設定返回碼為200,然後讀取一個檔案的內容,並寫入到返回訊息中。這樣一個簡單的web伺服器就完成了,可以用RESTClient測試一下。

HTTPS相對於HTTP增加了SSL通道,用戶端和伺服器端必須有相互信任的認證才可以通訊。自己對這方面的內容之前完全不瞭解,費了很大的功夫才初步把HTTPS的請求調通。

相比於HTTP的伺服器,HTTPS改動的地方主要是建立伺服器的時候:

class SecureHTTPServer(HTTPServer):

    def __init__(self, server_address, HandlerClass):

        BaseServer.__init__(self, server_address, HandlerClass)

        self.socket = ssl.SSLSocket(socket.socket(self.address_family,self.socket_type),keyfile=‘./server.key‘, certfile=‘./server.crt‘, server_side=True)

        self.server_bind()

        self.server_activate()

這裡新聲明了一個SecureHTTPServer類,繼承自HTTPServer類,在這個類中重新定義了建構函式,主要是新建立了一個SSLSocket類型的通訊端,並指定了這個通訊端的keyfile和certfile。keyfile和certfile這兩個檔案是安裝了OpenSSL後手動產生的,執行如下openssl命令在本地產生pem檔案:
req -new -x509 -keyout server.pem -out server.pem -day 365 -nodes
將server.pem檔案中CERTIFICATE部分拷貝出來另存新檔server.crt。執行如下命令在本地產生或者刪除認證:
keytool -import -alias certificatekey -file server.crt -keystore server.jks
keytool -delete -alias certificatekey -keystore server.jks
將server.jk上傳到發送請求的系統作為認證庫。


新聲明一個handler類來處理收到的請求,並添加了多線程機制:
class SecureHTTPHandler(CGIHTTPRequestHandler):
#     def setup(self):
#         self.connection = self.request
# #         self.rbufsize = 8192   
# #         self.wbufsize = 8192
#         self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
#         self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
    def commonProcess(self):
        #處理請求的通用函數
        try:
      #設定不阻塞
            self.request.setblocking(0)
      #設定逾時時間為5秒
            self.request.settimeout(5)
           #自己的處理代碼
        f = open(curdir + sep + self.path)
            print self.path
            print ‘This is a GET method!‘
            self.send_response(200)
            self.send_header(‘Content-type‘,
                             ‘text/html‘)
            self.end_headers()
            self.wfile.write(f.read())
            f.close()       
        except:
            logging.error(‘Invalid request:%s!‘ % self.path)
            self.send_error(404,‘Invalid request:%s!‘ % self.path)
           
    def do_GET(self):
        logging.info(‘Received url is %s‘ % self.path)
        logging.info(‘This is a GET method!‘)
        #self.commonProcess()
        t = threading.Thread(target = self.commonProcess,args = ())
        t.start()
        t.join(5)
           
    def do_POST(self):
        logging.info(‘Received url is %s‘ % self.path)
        logging.info(‘This is a POST method!‘)
        #self.commonProcess()
        t = threading.Thread(target = self.commonProcess,args = ())
        t.start()
        t.join(5)  
           
    def do_PUT(self):
        logging.info(‘Received url is %s‘ % self.path)
        logging.info(‘This is a PUT method!‘)
        #self.commonProcess()
        t = threading.Thread(target = self.commonProcess,args = ())
        t.start()
        t.join(5)
在main()函數中要聲明這個類的對象來建立伺服器:
    https_server = SecureHTTPServer(server_address,SecureHTTPHandler)

以下是用戶端的測試代碼:
import httplib

def main():

    conn = httplib.HTTPSConnection(host = "127.0.0.1", port = 8443, key_file=‘./server.key‘, cert_file=‘./server.crt‘ , source_address = (‘127.0.0.1‘,8080))

    print "requesting..."

    conn.request(‘PUT‘, ‘/test_body.txt‘)

    r1 = conn.getresponse()

    #列印響應碼和響應狀態資訊

 print r1.status, r1.reason
另外,python中的twisted架構在處理web伺服器時似乎功能很強大,後續可以深入研究一下。

 

python搭建簡單的web伺服器

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.