
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()
如果我把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()
之前所做的是靜態頁面的顯示,如果要顯示動態頁面的話就不能寫成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()))

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()