python写web服务器


 1 #coding = utf-8
 2 from http.server import BaseHTTPRequestHandler, HTTPServer
 3 
 4 class RequestHandler(BaseHTTPRequestHandler):
 5     Page = '''
 6         
 7         
 8         

Hello, world!

9 10 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     #代表一行,代表一列
 6     Page = '''
 7 
 8 
 9 10111213141516
Header Value
Date and time {date_time}
Client host {client_host}
Client port {client_port}
Command {command}
Path {path}
17 18 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         
13         
14         

Error accessing {path}

15

{msg}

16 17 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         
51         
52         

Error accessing {path}

53

{msg}

54 55 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 
 6 
 7 

Generated {0}

8 9 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         
 60         
 61         

Error accessing {path}

62

{msg}

63 64 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

相关