zoukankan      html  css  js  c++  java
  • Twisted的WEB开发

    1   简介

    在WEB开发中,偶尔需要对HTTP协议更多底层细节进行控制,这时的django/web.py等等显然无法满足要求,所以只好求助于Twisted了。使用Twisted进行WEB开发,其实更合适的叫法应该是基于HTTP服务器的开发,因为Twisted相对底层,所以可以控制的东西也比较底层。

    在Twisted的技术体系中,这个WEB开发实际上要涉及到HTTPChannel、HTTPFactory、Request三个层次的开发,以下详诉。

    HTTP协议参考 RFC2616 。

    2   Twisted技术体系

    Twisted技术体系包含2个层次:协议和工厂。协议负责连接成功以后对交互的处理,而工厂则是负责连接过程。在HTTP协议中,连接之后还有个生成HTTP请求报文的过程,所以构造出了一个Request对象来处理具体的一个HTTP请求的报文。

    在HTTP中的请求报文处理对象是 twisted.web.http.Request 类;HTTP的协议类是 twisted.web.http.HTTPChannel ;HTTP工厂是 twisted.web.http.HTTPFactory 。

    3   一个简单的例子

    节选自《Twisted网络编程必备》:

    from twisted.web import http
    
    class MyRequestHandler(http.Request):
        pages={
            '/':'<h1>Home</h1>Home Page',
            '/test':'<h1>Test</h1>Test Page',
            }
        def process(self):
            if self.pages.has_key(self.path):
                self.write(self.pages[self.path])
            else:
                self.setResponseCode(http.NOT_FOUND)
                self.write("<h1>Not Found</h1>Sorry, no such page.")
            self.finish()
    
    class MyHttp(http.HTTPChannel):
        requestFactory=MyRequestHandler
    
    class MyHttpFactory(http.HTTPFactory):
        protocol=MyHttp
    
    if __name__=="__main__":
        from twisted.internet import reactor
        reactor.listenTCP(8000,MyHttpFactory())
        reactor.run()

    与其他很多框架不同,TwistedWEB只有一个核心的请求处理类Request,各个针对不同的URL的请求也要通过这里来分发。而这个类只要重载process() 方法就可以了,期间的很多数据都可以通过self来引用。

    请求的处理流程也就是判断对不同URL的不同处理,然后向客户端写入响应信息,并在最后调用关闭请求。步骤如下:

    1. 过滤URL, self.path
    2. self.write(data) 向客户端写入数据
    3. self.finish() 关闭响应

    4   Twisted WEB Request参考

    来自分析 twisted.web.http.http.py 源代码。

    4.1   请求

    包含请求的数据,这里都是指Request类的成员。

    channel :包含上级的HTTP协议对象。

    transport :通信对象。

    method :HTTP方法,如GET和POST。

    uri :全部请求的URI。

    path :具体的请求路径,不含参数。

    args :请求参数,包括URL参数和POST参数。格式如 {'key':['val1','val2'],} 。

    received_headers :请求报文的头字段。

    received_cookies :请求报文的cookie。

    content :请求报文的实体主体,文件对象。

    clientproto :发出请求的客户端的HTTP版本。

    client :?

    host :?

    getHeader(key) :获取请求的头字段。

    getCookie(key) :获取请求的cookie。

    getAllHeaders() :所有请求的头字段字典,就是返回received_headers。

    getRequestHostname() :请求的host字段,不含端口号。

    getHost() :原始请求的通信地址,返回host。

    getClientIP() :获取客户端IP。

    getUser() :获取basic验证中的用户名。

    getPassword() :获取basic验证中的密码。

    getClient() :?

    4.2   响应

    包含响应的数据,这里都是Request类的成员。

    headers :字典,包含响应报文的头字段。

    cookies :字典,包含响应报文的cookie。

    finish() :结束响应报文。

    write(data) :向客户端发送数据,经过了HTTP包装了。

    addCookie(k,v,expires=None,domain=None,path=None,max_age=None,comment=None,secure=None):为响应报文添加一个cookie。

    setResponseCode(code,message=None) :设置响应代码,code参考常量定义。

    setHeader(k,v) :设置头字段。

    redirect(url) :HTTP重定向。

    setLastModified(when) :设置缓存超时,when的值为长整型的那个时间。

    setETag(etag) :设置缓存标志,用于在内容更改时让用户有所发觉。

    setHost(host,port,ssl=0) :设置请求地址。用于代理服务器的重定向。

    4.3   常量

    没有响应主体的code:

    NO_BODY_CODES=(204,304)

    responses=RESPONSES :字典,保存了各个响应码的对应提示信息。

    响应报文中的响应码:

    OK=200 :请求处理成功,最常见的响应代码,但是正因为常见,所以默认就是这个了,也无须设置到setResponseCode。

    NOT_MODIFIED=304 :请求的资源没有没有修改过,用于浏览器缓存。

    BAD_REQUEST=400 :请求报文有语法错误。

    UNAUTHORIZED=401 :尚未认证,要求用户输入认证信息。

    FORBIDDEN=403 :禁止访问。

    NOT_FOUND=404 :请求的资源不存在。

    INTERNAL_SERVER_ERROR=500 :服务器内部错误。

    NOT_IMPLEMENTED=501 :该功能尚未实现。

    BAD_GATEWAY=502 :请求路径错误。

    4.4   HTTPChannel

    构造函数无参数,处理HTTP报文。

    requestFactory=Request :指定了请求报文处理工厂。

    4.5   HTTPFactory

    __ini__(logPath=None,timeout=60*60*12) :构造函数可以设置日志和超时。

    buildProtocol(addr) :内部的构造协议对象的方法,不要调用。

    protocol=HTTPChannel :设置协议对象。

    5   比较完善的开发模式

    建立一个Request类的子类作为请求工厂,或者说请求发布器,其中有识别不同的URL并的能力,通过字典找到该URL对应的函数,调用这个函数并传递self参数。每个具体的请求处理函数也只有1个request参数,返回数据都是直接写入request.write()中。

    一般来说请求工厂的process()中需要设置响应类型,如网页的:

    self.setHeader("Content-Type","text/html; charset=GB2312")

    同时也要在没有对应的URL时告知客户端找不到:

    self.setResponseCode(http.NOT_FOUND)
    self.write("<h1>Not Found</h1>Sorry, no such page.")
    self.finish()

    至于self.finish()放在各个请求处理函数中还是放在process(),就是个人爱好问题了。比较推荐放在process()中。

    提取请求参数的重点在request.args字典,每个键都是映射到一个列表,为了适应HTTP提交中一个键对应多个值的情况,当然,你也可以只取第一个值。

    6   以resource方式提供WEB资源

    1. 每个资源都是 twisted.web.resource.Resource 的子类
    2. 可以自己定义构造函数
    3. 要重载 render(self,request) 方法来响应请求
    4. render 方法中的request对象实际就是Request的实例

    一个例子:

    from twisted.web import resource,static,server
    
    class HomePage(resource.Resource):
    
        def render(self,request):
            request.write("Home Page")
            return
    
        def getChild(self,path,request):
            return AnotherPage() #另外一个Resource的子类
    
    if __name__=="__main__":
        from twisted.internet import reactor
        root=resource.Resource()
        root.putChild('',HomePage())
        root.putChild('color',ColorRoot())
        root.putChild('style.css',static.File('style.css'))
        site=server.Site(root)
        reactor.listenTCP(8000,site)
        reactor.run()

    可以通过各个Resource的构造参数传入path参数,用以后来寻找下级Resource的参数。

    Note

    关于Resource还有很多细节,但是对本文意义不大,所以略。

    7   总结

    总的来说,用Twisted来开发更适合于开发个框架,而不是直接做WEB应用,有如一直都很少有人直接用 mod_python 来开发WEB应用一样。

  • 相关阅读:
    nandflash 分区相关
    android 动态渐变 字符效果
    《Java是如何快速煮成C#的?》(二):数据访问(1)
    01总体分布下的参数假设检验示例一
    《Java是如何快速煮成C#的?》(一):相似的方法(2)
    SQL Server 2008中SQL之WaitFor
    IIS进程经常崩溃的三个解决思路
    Trace.axdasp.net调试的新境界
    ClickOnce发布时报错:Cannot publish because a project failed to build
    《活法》中一个故事--令托尔斯泰也折服的人性寓言
  • 原文地址:https://www.cnblogs.com/dancesir/p/6977871.html
Copyright © 2011-2022 走看看