Python BaseHTTPServer 模块解析

#coding=utf-8
'''
Created on 2015-7-20

@author: xhw

@explain: 实现GET方法和POST方法请求
'''
from  BaseHTTPServer import HTTPServer,BaseHTTPRequestHandler
import urllib

class ServerHTTP(BaseHTTPRequestHandler):
    def do_GET(self):
        path = self.path
        print path
        #拆分url(也可根据拆分的url获取Get提交才数据),可以将不同的path和参数加载不同的html页面,或调用不同的方法返回不同的数据,来实现简单的网站或接口
        query = urllib.splitquery(path)
        print query
        self.send_response(200)
        self.send_header("Content-type","text/html")
        self.send_header("test","This is test!")
        self.end_headers()
        buf = '''<!DOCTYPE HTML>
                <html>
                <head><title>Get page</title></head>
                <body>
                
                <form action="post_page" method="post">
                  username: <input type="text" name="username" /><br />
                  password: <input type="text" name="password" /><br />
                  <input type="submit" value="POST" />
                </form>
                
                </body>
                </html>'''
        self.wfile.write(buf)
        
    def do_POST(self):
        path = self.path
        print path
        #获取post提交的数据
        datas = self.rfile.read(int(self.headers['content-length']))
        datas = urllib.unquote(datas).decode("utf-8", 'ignore')
        
        self.send_response(200)
        self.send_header("Content-type","text/html")
        self.send_header("test","This is test!")
        self.end_headers()
        buf = '''<!DOCTYPE HTML>
        <html>
            <head><title>Post page</title></head>
            <body>Post Data:%s  <br />Path:%s</body>
        </html>'''%(datas,self.path)
        self.wfile.write(buf)
        
def start_server(port):
    http_server = HTTPServer(('', int(port)), ServerHTTP)
    http_server.serve_forever() 
    
if __name__ == "__main__":
    start_server(8000)

http://python.jobbole.com/87392/

本文针对 python 2.7 版本,介绍了 BaseHTTPServer 这个库的使用方法。

这个库是 python 自带的标准库的一部分,不需要额外安装

在 linux 系统下,位置在 /usr/lib/python2.7/BaseHTTPServer.py

HTTP 协议

HTTP 请求(request)

http 请求分为三个部分:

  1. 第一行:请求类型、地址和版本号
  2. 头部信息:HTTP header
  3. 数据部分

标准的 HTTP 请求是:

GET / HTTP/1.1
Host: cizixs.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
If-Modified-Since: Thu, 25 Feb 2016 16:00:57 GMT
Cache-Control: max-age=0
标准的 HTTP 响应头部:
HTTP/1.1 304 Not Modified
Server: GitHub.com
Date: Thu, 24 Mar 2016 06:21:25 GMT
Last-Modified: Thu, 25 Feb 2016 16:00:57 GMT
access-control-allow-origin: *
Expires: Thu, 24 Mar 2016 06:31:25 GMT
Cache-Control: max-age=600
X-GitHub-Request-Id: 3AF60A59:7CE3:1C889201:56F38765
 
data...



BaseHTTPServer:

主要包含两个类HTTPServerBaseHTTPRequestHandler

HTTPServer:
    继承SocketServer.TCPServer,用于获取请求,并将请求分配给应答程序处理

BaseHTTPRequestHandler:
    继承SocketServer.StreamRequestHandler,对http连接的请求作出应答(response)
    
基于BaseHTTPServer 的Http Server的处理流程:
1.HTTPServer绑定对应的应答类(BaseHTTPRequestHandler )
    http_server = HTTPServer(('', int(port)), ServerHTTP)
2.监听端口:
    http_server.serve_forever() 
    serve_forever()方法使用select.select()循环监听请求,当接收到请求后调用
    当监听到请求时,取出请求对象
3.应答:
    创建新线程以连接对象(开始理解成请求对象)为参数实例化应答类:ServerHTTP()
    应答类根据请求方式调用ServerHTTP.do_XXX处理方法

常用方法/属性:

BaseHTTPRequestHandler.path                    #包含的请求路径和GET请求的数据
BaseHTTPRequestHandler.command                 #请求类型GET、POST...
BaseHTTPRequestHandler.request_version         #请求的协议类型HTTP/1.0、HTTP/1.1
BaseHTTPRequestHandler.headers                 #请求的头
BaseHTTPRequestHandler.responses               #HTTP错误代码及对应错误信息的字典
BaseHTTPRequestHandler.handle()                #用于处理某一连接对象的请求,调用handle_one_request方法处理
BaseHTTPRequestHandler.handle_one_request()    #根据请求类型调用do_XXX()方法,XXX为请求类型
BaseHTTPRequestHandler.do_XXX()                #处理请求
BaseHTTPRequestHandler.send_error()            #发送并记录一个完整的错误回复到客户端,内部调用send_response()方法实现
BaseHTTPRequestHandler.send_response()         #发送一个响应头并记录已接收的请求
BaseHTTPRequestHandler.send_header()           #发送一个指定的HTTP头到输出流。 keyword 应该指定头关键字,value 指定它的值
BaseHTTPRequestHandler.end_headers()           #发送一个空白行,标识发送HTTP头部结束
BaseHTTPRequestHandler.wfile    #self.connection.makefile('rb', self.wbufsize) self.wbufsize = -1 应答的HTTP文本流对象,可写入应答信息

BaseHTTPRequestHandler.rfile    #self.connection.makefile('wb', self.rbufsize) self.rbufsize = 0  请求的HTTP文本流对象,可读取请求信息


BaseHTTPServer 源代码解析

class BaseHTTPRequestHandler(request, client_address, server)

这个类被用来处理到达服务器的 HTTP 请求。

单独地,它不能响应任意实际的 HTTP 请求,必须是子类来处理每个请求方法 (例如, GET 或 POST)。BaseHTTPRequestHandler 通过子类为使用提供一些类和实例变量以及方法。

BaseHTTPServer 这个模块提供了两个类让开发者实现 HTTP server:HTTPServer 和 BaseHTTPRequestHandler

HTTPServer 继承了 SocketServer.BaseServer,主要功能是:创建和监听 socket,把请求转发给 handler 去处理。主要的工作都是在 BaseHTTPRequestHandler 中处理的,它把和请求有关的信息都封装成自己的实例变量,可以在子类中直接使用。这些变量包括:

  • client_address:客户端的地址,存放在一个 tuple 里 (host, port)
  • server: server 实例
  • command:请求类型,比如,GET、POST 等
  • path:请求路径,比如 /index.html
  • request_version: 请求版本号,比如 HTTP/1.0
  • headers:mimetools.Message 的实例对象,包含了头部信息
  • rfile:rfile 是一个输入流,用来读取请求的数据
  • wfile:wfile 是一个输出流,用来回写响应,回写的数据必须遵守 HTTP 协议的格式

除了这些实例变量之外,还有其他的类变量:

  • server_version:服务器的版本号,比如 BaseHTTP/0.2
  • sys_version:python 的版本号,比如 Python/1.4
  • error_message_format:错误 response 的格式
  • error_content_type:错误 response 的 Content-Type,默认是 text/html
  • protocol_version:HTTP 协议版本号
  • responses:error code 对应错误消息的匹配关系

当然,还有一些方法可以使用:

  • handle():调用底层的实现来处理一次请求
  • send_response():发送应答消息和状态码

更多的内容可以查看文末的链接。

为什么这个类不会被广泛使用?

写了这么多,我们也看到这个类缺点很多,比如:

  • 不支持 url 解析(我感觉可以支持url的???)和转发,如果有多个 endpoint,需要用户自己解析????
  • 回写的响应也需要用户自己维护格式,容易出错
  • 没有模板支持,如果要写 HTML 页面,也需要自己维护

所以在正式的工作中,编写 HTTP server 端应用的时候,都是使用 web 框架的。因为 web 框架帮你封装了底层的这些细节,还提供了很多便利的功能,让开发者把中心更多地放到业务逻辑的实现。


Guess you like

Origin blog.csdn.net/liulina603/article/details/79930372