Python 《Python实现简单Web服务器》实验报告

WechatIMG62.jpeg

环境

  • macOS 10.14.6

  • Python 3.7.7

  • httpie

httpie 是一个命令行 HTTP 客户端。

安装httpie

  • 安装
1
$ brew install httpie

这里使用 homebrew 安装 httpie。

  • 查看版本
1
2
$ http --version
2.2.0

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# -*- coding:utf-8 -*-

import sys, os, urllib, subprocess
import urllib.parse
import urllib.request
from http.server import BaseHTTPRequestHandler,HTTPServer
# -------------------------------------------------------------------------------

class ServerException(Exception):
'''服务器内部错误'''
pass

# -------------------------------------------------------------------------------

class base_case(object):
'''条件处理基类'''

def handle_file(self, handler, full_path):
try:
with open(full_path, 'rb') as reader:
content = reader.read()
handler.send_content(content)
except IOError as msg:
msg = "'{0}' cannot be read: {1}".format(full_path, msg)
handler.handle_error(msg)

def index_path(self, handler):
return os.path.join(handler.full_path, 'index.html')

def test(self, handler):
assert False, 'Not implemented.'

def act(self, handler):
assert False, 'Not implemented.'

# -------------------------------------------------------------------------------

class case_no_file(base_case):
'''文件或目录不存在'''

def test(self, handler):
return not os.path.exists(handler.full_path)

def act(self, handler):
raise ServerException("'{0}' not found".format(handler.path))

# -------------------------------------------------------------------------------

class case_cgi_file(base_case):
'''可执行脚本'''

def run_cgi(self, handler):
data = subprocess.check_output(["python3", handler.full_path],shell=False)
handler.send_content(data)

def test(self, handler):
return os.path.isfile(handler.full_path) and \
handler.full_path.endswith('.py')

def act(self, handler):
self.run_cgi(handler)

# -------------------------------------------------------------------------------

class case_existing_file(base_case):
'''文件存在的情况'''

def test(self, handler):
return os.path.isfile(handler.full_path)

def act(self, handler):
self.handle_file(handler, handler.full_path)

# -------------------------------------------------------------------------------

class case_directory_index_file(base_case):
'''在根路径下返回主页文件'''

def test(self, handler):
return os.path.isdir(handler.full_path) and \
os.path.isfile(self.index_path(handler))

def act(self, handler):
self.handle_file(handler, self.index_path(handler))

# -------------------------------------------------------------------------------

class case_always_fail(base_case):
'''默认处理'''

def test(self, handler):
return True

def act(self, handler):
raise ServerException("Unknown object '{0}'".format(handler.path))

# -------------------------------------------------------------------------------

class RequestHandler(BaseHTTPRequestHandler):
'''
请求路径合法则返回相应处理
否则返回错误页面
'''

Cases = [case_no_file(),
case_cgi_file(),
case_existing_file(),
case_directory_index_file(),
case_always_fail()]

# 错误页面模板
Error_Page = """\
<html>
<body>
<h1>Error accessing {path}</h1>
<p>{msg}</p>
</body>
</html>
"""

# 处理get请求
def do_GET(self):
try:

# 得到完整的请求路径
self.full_path = os.getcwd() + self.path
# 遍历所有的情况并处理
for case in self.Cases:
if case.test(self):
case.act(self)
break

# 处理异常
except Exception as msg:
self.handle_error(msg)

# 处理post请求
def do_POST(self):
datas = self.rfile.read(int(self.headers['content-length']))
self.send_content(datas)

# 处理异常
def handle_error(self, msg):
content = self.Error_Page.format(path=self.path, msg=msg)
self.send_content(content.encode("utf-8"), 404)

# 发送数据到客户端
def send_content(self, content, status=200):
self.send_response(status)
self.send_header("Content-type", "text/html")
self.send_header("Content-Length", str(len(content)))
self.end_headers()
self.wfile.write(content)

# -------------------------------------------------------------------------------

if __name__ == '__main__':
serverAddress = ('', 8080)
server = HTTPServer(serverAddress, RequestHandler)
server.serve_forever()

创建 server.py,内容如上。

运行

  • 启动服务器
1
$ python server.py &

&表示将这个任务放到后台去执行。

  • get 请求
1
2
3
4
5
6
7
8
9
10
11
12
13
$ http 0.0.0.0:8080/home.html
HTTP/1.0 404 Not Found
Content-Length: 152
Content-type: text/html
Date: Thu, 13 Aug 2020 06:22:48 GMT
Server: BaseHTTP/0.6 Python/3.7.7

<html>
<body>
<h1>Error accessing /home.html</h1>
<p>'/home.html' not found</p>
</body>
</html>
  • post 请求
1
2
3
4
5
6
7
8
9
10
$ http 0.0.0.0:8080 hello=world
HTTP/1.0 200 OK
Content-Length: 18
Content-type: text/html
Date: Thu, 13 Aug 2020 06:07:27 GMT
Server: BaseHTTP/0.6 Python/3.7.7

{
"hello": "world"
}
-------------本文结束感谢您的阅读-------------
0%