Python HTTP 请求-响应 模型,HTTP协议几乎是无状态的,即用户代理(或浏览器)发出请求后服务器提供响应。对于不涉及cookie的服务,客户端程序可以从函数式角度处理协议。我们可以使用http.client
和urllib
库来构建客户端。一个HTTP用户代理实际执行的内容如下所示:
import urllib.request
def urllib_demo(url):
with urllib.request.urlopen(url) as response:
print(response.read())
urllib_demo("http://slott-softwarearchitect.blogspot.com")
wget和curl1等程序使用以命令行参数形式提供的URL来完成这种处理。浏览器会响应用户的指示和点击操作,URL则来自用户的操作,这种操作通常是指点击链接文本或图像。
然而,对UX(user experience,用户体验)设计的实际考量会导致一些有状态的实现细节。当客户端必须跟踪cookie信息时,它就会变成有状态的。响应头会提供cookie,并且后续的请求必须将cookie返回给服务器,稍后将详细讨论该问题。
HTTP响应会包含一个需要用户代理端进行额外操作的状态码。300~399范围内的许多状态码表明请求的资源已经被移走了。用户代理随后需要保存来自Location
报头的详细信息,并请求一个新的URL。401
状态码表明需要认证,因此用户代理必须使用包含访问服务器所需凭证的Authorization
报头来发起新的请求。库urllib
可以处理有状态客户端的请求。库http.client
不会自动跟随3xx
的重定向状态码。
用户代理处理3xx
和401
代码的技术可以通过简单的递归实现。如果状态不表示重定向,则为基础情况,函数返回结果。如果需要重定向,则可以使用重定向地址递归地调用该函数。
考虑协议的另一面:一个静态内容的服务器可以是无状态的。对于此,可以如下所示使用http.server
库:
from http.server import HTTPServer, def server_demo():
httpd = HTTPServer(
('localhost', 8080), SimpleHTTPRequestHandler)
while True:
httpd.handle_request()
httpd.shutdown()
上面创建了一个服务器对象,并将其赋给了httpd
变量。我们提供了监听连接请求所需的地址和端口号。TCP/IP协议会在一个单独的端口创建新的连接。HTTP协议会从这个端口读取请求并创建该句柄的实例。
在本例中,我们提供了SimpleHTTPRequestHandler
类来初始化每个请求。这个类必须实现一个最小的接口子集,用于向客户端先发送报头再发送响应体。这个特定类会提供本地目录中的文件。如果想自定义功能,可以创建一个子类,实现do_GET()
和do_GET()
等方法来改变其行为。
通常使用serve_forever()
方法,而不是手动编写循环。这里展示循环的使用是为了说明如果需要停止服务器,则必须关闭服务器。