当然,大多数人都不会想要编辑他们的网络服务器的源代码来增加新的功能。为了从这种不得不这么做的泥沼中解脱出来,服务器一直支持一个叫做通用网关接口(CGI)的机制,这为Web服务器为了满足请求去运行外部程序提供了一种标准方法。
例如,假设我们希望服务器能在HTML页面中显示本地时间。我们在只有几行代码的独立的程序中就可以做到:
为了使Web服务器运行该程序,我们添加如下的case handler:
test方法很简单:文件路径是以.py结尾吗?如果是,RequestHandler运行此程序。
这是非常不安全的:如果有人知道我们的服务器上的一个Python文件的路径,我们就只能任他们运行它,不管它访问了什么数据,它是否包含了一个无限循环,或任何其他什么(2)
先不管那个,核心的思想很简单:
1.在子进程中运行程序。
2.捕获任何子进程发送到标准输出的内容。
3.把内容发送回发出请求的客户端。
完整的CGI协议比这个要丰富的多-尤其是它允许url中服务器传递给程序的参数运行-但这些细节不影响系统的整体架构...这再次变得相当乱。 RequestHandler中最初有一个方法handle_file,用于处理内容。现在,我们已经在list_dir和run_cgi表中加入了两种特殊情况。这三个方法并不真正在所属类起作用,因为他们主要由其他方法使用。
修补程序很简单:为所有的case handler创建一个父类,当(且仅当)他们由两个或多个handler共享时,把其他方法移入这个类。当我们完成后,RequestHandler类看起来是这样的:
与此同时case handler的父类是:
现有的文件(只是挑选随机的一例)的handler是:
讨论
我们原始代码和重构版本之间的差异反映了两个重要思想。首先是考虑类作为相关服务的集合。services.RequestHandler和base_case不作决定或采取行动;它们提供让其他类使用去做这些事的工具。
第二个是可扩展性:人们可以通过编写一个外部CGI程序,或通过添加一个case处理器的类,来给我们的Web服务器添加新功能。后者确实需要更改RequestHandler的一行(在Cases列表插入case handler),但我们可以通过Web服务器读取一个配置文件和负载handler类来避免。在这两种情况下,它们可以忽略更低层级的细节,正如BaseHTTPRequestHandler类的作者已经允许我们忽略处理套接字连接和解析HTTP请求的细节。
这些想法通常是有用的;看看你能不能想办法在自己的项目中使用它们。
-------------------------------------------------------------------------------------------------------------------
1.在本章中,包括一些情况下,状态代码404不合适的地方,我们会好几次使用handle_error。当你继续阅读,试着想想你将如何扩展程序使状态响应代码可以很容易地在每种情况下被提供
2.我们的代码还使用了popen2库函数,该函数为支持subprocess模块已经被弃用了。然而,在这个例子中,popen2是较少分散使用的工具。
例如,假设我们希望服务器能在HTML页面中显示本地时间。我们在只有几行代码的独立的程序中就可以做到:
为了使Web服务器运行该程序,我们添加如下的case handler:
test方法很简单:文件路径是以.py结尾吗?如果是,RequestHandler运行此程序。
这是非常不安全的:如果有人知道我们的服务器上的一个Python文件的路径,我们就只能任他们运行它,不管它访问了什么数据,它是否包含了一个无限循环,或任何其他什么(2)
先不管那个,核心的思想很简单:
1.在子进程中运行程序。
2.捕获任何子进程发送到标准输出的内容。
3.把内容发送回发出请求的客户端。
完整的CGI协议比这个要丰富的多-尤其是它允许url中服务器传递给程序的参数运行-但这些细节不影响系统的整体架构...这再次变得相当乱。 RequestHandler中最初有一个方法handle_file,用于处理内容。现在,我们已经在list_dir和run_cgi表中加入了两种特殊情况。这三个方法并不真正在所属类起作用,因为他们主要由其他方法使用。
修补程序很简单:为所有的case handler创建一个父类,当(且仅当)他们由两个或多个handler共享时,把其他方法移入这个类。当我们完成后,RequestHandler类看起来是这样的:
与此同时case handler的父类是:
现有的文件(只是挑选随机的一例)的handler是:
讨论
我们原始代码和重构版本之间的差异反映了两个重要思想。首先是考虑类作为相关服务的集合。services.RequestHandler和base_case不作决定或采取行动;它们提供让其他类使用去做这些事的工具。
第二个是可扩展性:人们可以通过编写一个外部CGI程序,或通过添加一个case处理器的类,来给我们的Web服务器添加新功能。后者确实需要更改RequestHandler的一行(在Cases列表插入case handler),但我们可以通过Web服务器读取一个配置文件和负载handler类来避免。在这两种情况下,它们可以忽略更低层级的细节,正如BaseHTTPRequestHandler类的作者已经允许我们忽略处理套接字连接和解析HTTP请求的细节。
这些想法通常是有用的;看看你能不能想办法在自己的项目中使用它们。
-------------------------------------------------------------------------------------------------------------------
1.在本章中,包括一些情况下,状态代码404不合适的地方,我们会好几次使用handle_error。当你继续阅读,试着想想你将如何扩展程序使状态响应代码可以很容易地在每种情况下被提供
2.我们的代码还使用了popen2库函数,该函数为支持subprocess模块已经被弃用了。然而,在这个例子中,popen2是较少分散使用的工具。