使用wsgiref库diy简单web架构

1.了解CGI和WSGI(1)CGICGI(CommonGatewayInterface)通用网关接口,即接口协议,前端向服务器发送一个URL(携带请求类型、参数、cookie等信息)请求,

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

1. 了解CGI和WSGI

(1)CGI

  CGI(Common Gateway Interface)通用网关接口,即接口协议,前端向服务器发送一个URL(携带请求类型、参数、cookie等信息)请求,服务器把这个请求的各种参数写进进程的环境变量,比如
REQUEST_METHOD,PATH_INFO之类的,然后开启 cgi模块以后,将其发送给CGI程序,CGI程序(可以由各种语言编写,比如C、C ++、VB 和Delphi 等)从环境变量中解析出各种参数,然后向标准输出输出内容(比如cout了一段HTML代码),这些内容没有被打印到控制台上,而是最终响应给了你的浏览器,渲染出了网页。每一次向CGI发送请求,都会生成一个CGI进程,这就是所谓的fork-and-exec模式,这也通常是导致并发瓶颈的症结,反向代理加上大型的的分布式系统可以一定程度上减轻这些压力。

(2)WSGI

  WSGI(Python Web Server Gateway Interface,缩写为WSGI)web服务器网关接口,也是接口协议,前端向服务器发送一个URL(携带请求类型、参数、cookie等信息)请求,服务器把这个请求的各种参数传给WSGI模块,wsgi将各种参数进行python化,封装为request对象传递给按照WSGI接口标准调用注册的WSGI Application,并返回response参数给客户端。

2. wsgiref库简介

  wsgiref是python内置库,实现了一个简单的WSGI Server和WSGI Application,使用该库我们将很容易实现自定义的web架构而不用考虑TCP/HTTP层协议,库源码位于/django/lib/wsgiref文件夹,该库提供了5个模块:

* util -- Miscellaneous useful functions and wrappers

* headers -- Manage response headers

* handlers -- base classes for server/gateway implementations

* simple_server -- a simple BaseHTTPServer that supports WSGI

* validate -- validation wrapper that sits between an app and a server
                  to detect errors in either
                                            

 下面主要对simple_server模块的重点函数和使用方法进行说明

3. wsgiref.simple_server类使用及部分源码分析

(1)先上一段代码

  该代码来自simple_server.py的最后7行

if __name__ == '__main__':
    with make_server('', 8000, demo_app) as httpd:
        sa = httpd.socket.getsockname()
        print("Serving HTTP on", sa[0], "port", sa[1], "...")
        import webbrowser
        webbrowser.open('http://localhost:8000/xyz?abc')
        httpd.handle_request()  # serve one request, then exit

  这段代码表达两个意思:启动服务—->处理http://localhost:8000/xyz?abc请求

(2)分析make_server启动服务过程

  使用wsgiref库diy简单web架构

  server_class传入两个参数,第一个元组(host,ip),第二个WSGIRequestHandler类,第一个参数用于socketserver.TCPServer启动服务(图中标记1),第二个参数WSGIRequestHandler用于BaseServer类初始化self.RequestHandlerClass属性(图中标记2),用于finish_request()函数进行对象初始化(图中的标记3),主要目的实现后面回调函数调用

(3)分析handle_request()函数处理过程

  该函数的实现过程在基类BaseServer中,该函数主要实现以下功能(这里不讨论epoll异步并发,相关epoll的内容可以看我之前的博客):

  get_request()—->verify_request()—->process_request()—->shutdown_request()

  单看函数名就应该明白整个流程了

(4)现在到重点了,看demo_app回调是如何实现的

  接下来主要分析下make_server()函数的第三个参数demo_app是如何实现调用的

  通过源码我们看到,finish_request()函数中实现了RequestHandlerClass初始化,也就是WSGIRequestHandler初始化

def finish_request(self, request, client_address):
        """Finish one request by instantiating RequestHandlerClass."""
        self.RequestHandlerClass(request, client_address, self)

  来张图一看什么都清楚了

  使用wsgiref库diy简单web架构

  a. 服务启动后,WSGIServer通过set_app将回调函数保存起来

  b. finish_request()对WSGIRequestHandler进行实例化,调用其基类BaseRequestHandle的构造函数,构造函数中又调用了handle处理函数,由于派生类WSGIRequestHandler重写了handle方法,实则调用的是WSGIRequestHandler类的handle函数,如上图标记3,得到回调函数对象,并执行。

def run(self, application):
        try:
            self.setup_environ()
            self.result = application(self.environ, self.start_response)
            self.finish_response()
            。。。。。。。。。。。。。。

  到现在为止一切就都清楚了!接下来就可以自由的对回调函数进行处理了!

4. DIY web架构

  模仿django架构的model—->route—->view—>template模型实现http请求,显示网页

(1)models.py

  使用redis的创建两个字符串结构name和url

import redis

class Model:
    def __init__(self):
        conn = redis.Redis()
        self.name = conn.get('name')
        self.url = conn.get('url')

(2)urls.py

import views

urlpattern = ((r'/fate0729/', views.login),)

(3)views.py

  实现通过model对模板进行渲染

from models import Model
import re

def render(html_path, **wargvs):
    with open(html_path, 'r') as pf:
        data = ''.join(pf.readlines())
        print(data)

    if wargvs is not None:
        # 为了测试这里使用了固定格式obj.attr
        results = re.findall(r'{{(.*)}}', data)
        for result in results:
            obj_attr_list = result.partition('.')
            obj = wargvs.get(obj_attr_list[0])
            attr = obj_attr_list[-1]
            regex = r'{{.*\.%s}}' %(attr)
            value = getattr(obj,attr).decode('utf-8')
            print(attr,value)
            data = re.sub(regex,str(value), data)
    return data.encode('utf-8')

def login(request):
    model = Model()
    return render('web.html', **{'model':model})

(4)main.py

from wsgiref.simple_server import make_server
import urls

def routers():
    urlpattern=urls.urlpattern
    return urlpattern

def applications(environ,start_response):
    path=environ.get("PATH_INFO")
    start_response('200 OK', [('Content-Type', 'text/html'),('Charset', 'utf8')])

    urlpattern=routers()
    func=None
    for item in urlpattern:
        if path==item[0]:
            func=item[1]
            break
    if func:
        return [func(environ)]
    else:
        return [b"<h1>404!<h1>"]

if __name__ == '__main__':
    conn = make_server('127.0.0.1', 8001, applications)
    print('server is working...')
    conn.serve_forever()

(5)测试

  python main.py

  打开浏览器输入:127.0.0.1/fate0729/

  使用wsgiref库diy简单web架构

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/120042.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Redis – 底层数据结构与持久化简述

    Redis – 底层数据结构与持久化简述不啰嗦,我们直接开始!一、redis底层数据结构1.sds结构Redis中并没有直接使用C语言中的字符串,而是定义了一种简单动态字符串(simpledynamicstring)作为Redis的默认字符串实现,简称SDS。在Redis中,C语言的字符串只会用于一些无需对字符串修改的地方,如日志打印等。而Redis默认的字符串实现是SDS,如set命令中的key底层即是一个SDS,而value如果是一个字符串类型,则底层也是SDS,如果value是列表,则列表里的每个元素底层都是SDS。

  • gridview属性_datagridview设置列宽

    gridview属性_datagridview设置列宽usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.Drawing;usingSystem.Windows.Forms;classSetDataViewGirdStyle{   privatestaticColor_mLinearBeginColor;

  • Delphi中强制IdHTTP使用HTTP1.1(转)

    Delphi中强制IdHTTP使用HTTP1.1(转)Delphi中强制IdHTTP使用HTTP1.1(转)标签:delphiwindows工具server2011-07-1807:46952人阅读评论(0)收藏举报分类:DelphiIdHttp控件(29)前两天帮人写程序用IdHTTP控件往一网站发包如下:Delphi代码IdHTTP1.Request.Connection:=’Keep-A…

  • 运维架构体系搭建系列-目录篇[通俗易懂]

    运维架构体系搭建系列-目录篇[通俗易懂]前言:去年新加入的一家公司,传统企业这里就不说名字了,不过公司规模还是有的,鄙人来之前基本上用的都是saas产品,加上疫情原因,没及时跳坑,做为一个半吊子自动化运维开发当然是选择先混日子,后面等来了一个新的技术团队,开始做自己的系统和产品。一、云选型及网络规划1、云产品选型2、网络规划二、devops相关服务搭建1、cicd工具链搭建2、项目管理三、db&中间件1、数据库管理2、中间件管理四、k8s环境及微服务治理1、k8s选型及搭建2、mse管理五、监控&日志

  • C++多线程函数CreateThread()详解

    C++多线程函数CreateThread()详解采用CreateThread()创建多线程程序原创2012年12月10日11:44:5936683…

  • 使用 Vagrant+Docker 构建 PHP 最优开发环境[通俗易懂]

    使用 Vagrant+Docker 构建 PHP 最优开发环境

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号