python寫web服務器


 

 1 #coding = utf-8
 2 from http.server import BaseHTTPRequestHandler, HTTPServer
 3 
 4 class RequestHandler(BaseHTTPRequestHandler):
 5     Page = '''
 6         <html>
 7         <body>
 8         <p>Hello, world!</p>
 9         </body>
10         </html>
11         '''
12     #重載do_GET方法
13     def do_GET(self):
14         self.send_response(200)  #發送狀態碼,200是ok
15         self.send_header('Content-Type', 'text/html')
16         '''
17         發送http頭部信息,text/html指HTML格式
18         另外還有諸如text/plain純文本格式,image/gif GIF圖片格式
19         通過頭部信息瀏覽器就知道如何處理所發來的內容了
20         另外還有self.send_header('Content-Encoding','gzip')是指讓瀏覽器按照壓縮方式處理內容
21         另外還有很多。。。
22         '''
23         self.end_headers()
24         self.wfile.write(self.Page.encode())
25 
26 #----------------------------------------------------------------------
27 
28 if __name__ == '__main__':
29     serverAddress = ('', 8080)
30     server = HTTPServer(serverAddress, RequestHandler)
31     server.serve_forever()
簡單的web服務器

如果我把self.send_response(200)狀態碼改為404,那么就會出現下述情況:

 

 1 #coding = utf-8
 2 from http.server import BaseHTTPRequestHandler, HTTPServer
 3 
 4 class RequestHandler(BaseHTTPRequestHandler):
 5     #<tr>代表一行,<td>代表一列
 6     Page = '''
 7 <html>
 8 <body>
 9 <table>
10 <tr>  <td>Header</td>         <td>Value</td>          </tr>   
11 <tr>  <td>Date and time</td>  <td>{date_time}</td>    </tr>
12 <tr>  <td>Client host</td>    <td>{client_host}</td>  </tr>
13 <tr>  <td>Client port</td>    <td>{client_port}</td> </tr>
14 <tr>  <td>Command</td>        <td>{command}</td>      </tr>
15 <tr>  <td>Path</td>           <td>{path}</td>         </tr>
16 </table>
17 </body>
18 </html>
19         '''
20 
21     def do_GET(self):
22         page = self.create_page()
23         self.send_content(page)
24 
25     def send_content(self, page):
26         self.send_response(200)
27         self.send_header('Content-Type', 'text/html')
28         self.end_headers()
29         self.wfile.write(page.encode())
30 
31     def create_page(self):
32         values = {
33             'date_time': self.date_time_string(),
34             'client_host': self.client_address[0],
35             'client_port': self.client_address[1],
36             'command': self.command,
37             'path': self.path
38         }
39         page = self.Page.format(**values)
40         '''
41         字符串格式化函數
42         通過字典設置參數
43         site = {'name': '菜鳥教程', 'url': 'www.runoob.com'}
44         print('網站名:{name}, 地址:{url}'.format(**site))
45         '''
46         return page
47 
48 #----------------------------------------------------------------------
49 
50 if __name__ == '__main__':
51     serverAddress = ('', 8080)
52     server = HTTPServer(serverAddress, RequestHandler)
53     server.serve_forever()
顯示請求的信息

 

 1 #coding = utf-8
 2 from http.server import BaseHTTPRequestHandler, HTTPServer
 3 import sys, os
 4 
 5 
 6 class serverException(Exception):
 7     '''服務器內部錯誤'''
 8     pass
 9 
10 class RequestHandler(BaseHTTPRequestHandler):
11     errorPage = """\
12         <html>
13         <body>
14         <h1>Error accessing {path}</h1>
15         <p>{msg}</p>
16         </body>
17         </html>
18         """
19 
20     def do_GET(self):
21         try:
22             fullPath = os.getcwd() + self.path
23             if not os.path.exists(fullPath):  #不存在就報錯
24                 raise serverException("'{0}' not found".format(self.path))
25             elif os.path.isfile(fullPath):   #如果是文件,則打開
26                 self.handle_file(fullPath)
27             else:      #其余情況
28                 raise serverException("Unknown object '{0}'".format(self.path))
29         except Exception as msg:
30             self.handle_error(msg)
31 
32     def handle_error(self, msg):
33         content = self.errorPage.format(path=self.path, msg=msg)
34         self.send_content(content, 404)
35 
36     def send_content(self, page, status=200):
37         self.send_response(status)
38         self.send_header('Content-Type', 'text/html')
39         self.end_headers()
40         self.wfile.write(page.encode())
41 
42     def handle_file(self, fullPath):
43         try:
44             f = open(fullPath, 'r')   #python3要注意是以r讀還是rb讀
45             content = f.read()
46             self.send_content(content)
47         except IOError as msg:
48             msg = "'{0}' cannot be read: {1}".format(self.path, msg)
49             self.handle_error(msg)
50 
51 #----------------------------------------------------------------------
52 
53 if __name__ == '__main__':
54     serverAddress = ('', 8080)
55     server = HTTPServer(serverAddress, RequestHandler)
56     server.serve_forever()
響應靜態頁面

在這里的話需要把plain.html這個文件放在代碼相同目錄下。
測試情況如下:

 

 1 #coding = utf-8
 2 from http.server import BaseHTTPRequestHandler, HTTPServer
 3 import sys, os
 4 
 5 
 6 class serverException(Exception):
 7     '''服務器內部錯誤'''
 8     pass
 9 
10 '''
11 將不同的情況單獨寫成一個類,最后將這些類保存在一個列表之中,這樣最后遍歷列表即可,不需要if-elif了
12 '''
13 class case_no_file(object):
14     '''路徑不存在'''
15     def test(self, handler):
16         return not os.path.exists(handler.fullPath)
17     def act(self, handler):
18         raise serverException("'{0}' not found".format(handler.path))
19 
20 class case_is_file(object):
21     '''路徑是文件'''
22     def test(self, handler):
23         return os.path.isfile(handler.fullPath)
24     def act(self, handler):
25         handler.handle_file(handler.fullPath)
26 
27 class case_always_fail(object):
28     '''不滿足時的默認處理類'''
29     def test(self, handler):
30         return True
31     def act(self, handler):
32         raise serverException("Unknown object '{0}'".format(handler.Path))
33 
34 class case_directory_index_file(object):
35     '''進入根目錄時顯示主頁'''
36     def index_path(self, handler):
37         return os.path.join(handler.fullPath, 'index.html')   #前后合並
38     def test(self, handler):
39         return os.path.isdir(handler.fullPath) and os.path.isfile(self.index_path(handler))
40     def act(self, handler):
41         handler.handle_file(self.index_path(handler))
42 
43 class RequestHandler(BaseHTTPRequestHandler):
44     caseList = [case_no_file(),
45                 case_is_file(),
46                 case_directory_index_file(),
47                 case_always_fail()]
48 
49     errorPage = """\
50         <html>
51         <body>
52         <h1>Error accessing {path}</h1>
53         <p>{msg}</p>
54         </body>
55         </html>
56         """
57 
58     def do_GET(self):
59         try:
60             self.fullPath = os.getcwd() + self.path
61             for case in self.caseList:
62                 if case.test(self):
63                     case.act(self)
64                     break
65         except Exception as msg:
66             self.handle_error(msg)
67 
68     def handle_error(self, msg):
69         content = self.errorPage.format(path=self.path, msg=msg)
70         self.send_content(content, 404)
71 
72     def send_content(self, page, status=200):
73         self.send_response(status)
74         self.send_header('Content-Type', 'text/html')
75         self.end_headers()
76         self.wfile.write(page.encode())
77 
78     def handle_file(self, fullPath):
79         try:
80             f = open(fullPath, 'r')   #python3要注意是以r讀還是rb讀
81             content = f.read()
82             self.send_content(content)
83         except IOError as msg:
84             msg = "'{0}' cannot be read: {1}".format(self.path, msg)
85             self.handle_error(msg)
86 
87 #----------------------------------------------------------------------
88 
89 if __name__ == '__main__':
90     serverAddress = ('', 8080)
91     server = HTTPServer(serverAddress, RequestHandler)
92     server.serve_forever()
在url根目錄顯示主頁

 

之前所做的是靜態頁面的顯示,如果要顯示動態頁面的話就不能寫成html的文件了,在這里可以使用CGI協議與腳本來實現動態頁面。

服務器在收到客戶端的請求后執行指定的CGI應用程序,CGI應用程序執行后再轉換成服務器和瀏覽器能夠理解的內容,比如說HTML頁面。

下面的例子就是做一個展示當前時間的頁面,先是用python實現了一個CGI腳本time.py,當瀏覽器請求這個CGI腳本的時候,服務器就會去執行time.py,然后得到執行結果的一段HTML形式的字符,最后就輸出即可。

在這里就用到了python庫中的subprocess模塊,它的功能使fork一個子進程,然后運行一個外部程序。

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)

它的作用是執行args中的命令,並將其輸出成字符串返回。

 1 #!/usr/bin/env python
 2 import time
 3 
 4 print('''\
 5 <html>
 6 <body>
 7 <p>Generated {0}</p>
 8 </body>
 9 </html>
10 '''.format(time.asctime()))
time.py
  1 #coding = utf-8
  2 from http.server import BaseHTTPRequestHandler, HTTPServer
  3 import sys, os
  4 import subprocess
  5 
  6 
  7 class serverException(Exception):
  8     '''服務器內部錯誤'''
  9     pass
 10 
 11 '''
 12 將不同的情況單獨寫成一個類,最后將這些類保存在一個列表之中,這樣最后遍歷列表即可,不需要if-elif了
 13 '''
 14 class case_no_file(object):
 15     '''路徑不存在'''
 16     def test(self, handler):
 17         return not os.path.exists(handler.fullPath)
 18     def act(self, handler):
 19         raise serverException("'{0}' not found".format(handler.path))
 20 
 21 class case_is_file(object):
 22     '''路徑是文件'''
 23     def test(self, handler):
 24         return os.path.isfile(handler.fullPath)
 25     def act(self, handler):
 26         handler.handle_file(handler.fullPath)
 27 
 28 class case_always_fail(object):
 29     '''不滿足時的默認處理類'''
 30     def test(self, handler):
 31         return True
 32     def act(self, handler):
 33         raise serverException("Unknown object '{0}'".format(handler.Path))
 34 
 35 class case_directory_index_file(object):
 36     '''進入根目錄時顯示主頁'''
 37     def index_path(self, handler):
 38         return os.path.join(handler.fullPath, 'index.html')   #前后合並
 39     def test(self, handler):
 40         return os.path.isdir(handler.fullPath) and os.path.isfile(self.index_path(handler))
 41     def act(self, handler):
 42         handler.handle_file(self.index_path(handler))
 43 
 44 class case_cgi_file(object):
 45     '''腳本文件處理'''
 46     def test(self, handler):
 47         return os.path.isfile(handler.fullPath) and handler.fullPath.endswith('.py')
 48     def act(self, handler):
 49         handler.run_cgi(handler.fullPath)
 50 
 51 class RequestHandler(BaseHTTPRequestHandler):
 52     caseList = [case_no_file(),
 53                 case_cgi_file(),
 54                 case_is_file(),
 55                 case_directory_index_file(),
 56                 case_always_fail()]
 57 
 58     errorPage = """\
 59         <html>
 60         <body>
 61         <h1>Error accessing {path}</h1>
 62         <p>{msg}</p>
 63         </body>
 64         </html>
 65         """
 66 
 67     def do_GET(self):
 68         try:
 69             self.fullPath = os.getcwd() + self.path
 70             for case in self.caseList:
 71                 if case.test(self):
 72                     case.act(self)
 73                     break
 74         except Exception as msg:
 75             self.handle_error(msg)
 76 
 77     def handle_error(self, msg):
 78         content = self.errorPage.format(path=self.path, msg=msg)
 79         self.send_content(content, 404)
 80 
 81     def send_content(self, page, status=200):
 82         self.send_response(status)
 83         self.send_header('Content-Type', 'text/html')
 84         self.end_headers()
 85         self.wfile.write(page.encode())
 86 
 87     def handle_file(self, fullPath):
 88         try:
 89             f = open(fullPath, 'r')   #python3要注意是以r讀還是rb讀
 90             content = f.read()
 91             self.send_content(content)
 92         except IOError as msg:
 93             msg = "'{0}' cannot be read: {1}".format(self.path, msg)
 94             self.handle_error(msg)
 95 
 96     def run_cgi(self, fullPath):
 97         data = subprocess.check_output(['python', fullPath])
 98         self.send_content(data.decode())
 99 
100 #----------------------------------------------------------------------
101 
102 if __name__ == '__main__':
103     serverAddress = ('', 8080)
104     server = HTTPServer(serverAddress, RequestHandler)
105     server.serve_forever()
main.py

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM