python写web服务器
分类:
IT文章
•
2022-03-26 11:29:05
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()