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个模块:

  1. * util -- Miscellaneous useful functions and wrappers
  2.  
  3. * headers -- Manage response headers
  4.  
  5. * handlers -- base classes for server/gateway implementations
  6.  
  7. * simple_server -- a simple BaseHTTPServer that supports WSGI
  8.  
  9. * validate -- validation wrapper that sits between an app and a server
  10. to detect errors in either

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

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

(1)先上一段代码

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

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

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

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

  

  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初始化

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

  来张图一看什么都清楚了

  

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

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

  1. def run(self, application):
  2. try:
  3. self.setup_environ()
  4. self.result = application(self.environ, self.start_response)
  5. self.finish_response()
  6. 。。。。。。。。。。。。。。

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

4. DIY web架构

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

(1)models.py

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

  1. import redis
  2.  
  3. class Model:
  4. def __init__(self):
  5. conn = redis.Redis()
  6. self.name = conn.get('name')
  7. self.url = conn.get('url')

(2)urls.py

  1. import views
  2.  
  3. urlpattern = ((r'/fate0729/', views.login),)

(3)views.py

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

  1. from models import Model
  2. import re
  3.  
  4. def render(html_path, **wargvs):
  5. with open(html_path, 'r') as pf:
  6. data = ''.join(pf.readlines())
  7. print(data)
  8.  
  9. if wargvs is not None:
  10. # 为了测试这里使用了固定格式obj.attr
  11. results = re.findall(r'{{(.*)}}', data)
  12. for result in results:
  13. obj_attr_list = result.partition('.')
  14. obj = wargvs.get(obj_attr_list[])
  15. attr = obj_attr_list[-]
  16. regex = r'{{.*\.%s}}' %(attr)
  17. value = getattr(obj,attr).decode('utf-8')
  18. print(attr,value)
  19. data = re.sub(regex,str(value), data)
  20. return data.encode('utf-8')
  21.  
  22. def login(request):
  23. model = Model()
  24. return render('web.html', **{'model':model})

(4)main.py

  1. from wsgiref.simple_server import make_server
  2. import urls
  3.  
  4. def routers():
  5. urlpattern=urls.urlpattern
  6. return urlpattern
  7.  
  8. def applications(environ,start_response):
  9. path=environ.get("PATH_INFO")
  10. start_response('200 OK', [('Content-Type', 'text/html'),('Charset', 'utf8')])
  11.  
  12. urlpattern=routers()
  13. func=None
  14. for item in urlpattern:
  15. if path==item[]:
  16. func=item[]
  17. break
  18. if func:
  19. return [func(environ)]
  20. else:
  21. return [b"<h1>404!<h1>"]
  22.  
  23. if __name__ == '__main__':
  24. conn = make_server('127.0.0.1', , applications)
  25. print('server is working...')
  26. conn.serve_forever()

(5)测试

  python main.py

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

  

使用wsgiref库diy简单web架构的更多相关文章

  1. 2、基于wsgiref模块DIY一个web框架

    一 web框架 Web框架(Web framework)是一种开发框架,用来支持动态网站.网络应用和网络服务的开发.这大多数的web框架提供了一套开发和部署网站的方式,也为web行为提供了一套通用的方 ...

  2. mysql 主从同步出问题,重新修复从库 - web架构研究

    mysql 主从同步出问题,重新修复从库 - web架构研究     mysql 主从同步出问题,重新修复从库    0     昨天由于操作失误,在从库上执行一堆sql之后,导致主从同步错误,并且已 ...

  3. web架构设计经验分享(转)

    本人作为一位web工程师,着眼最多之处莫过于 性能与架构,本次幸得参与sd2.0大会,得以与同行广泛交流,于此二方面,有些心得,不敢独享,与众博友分享,本文是这次参会与众同撩交流的心得,有兴趣者可以查 ...

  4. Web 架构师的能力(转)

    文/刘如鸿 最近和几个朋友在谈到时下流行的Web 2.0,也提到了其中最重要的角色——架构师.多方各有争执,不外乎是因为背景和视角的缘故,包括架构一词,本身就从建筑学借鉴而来,至于架构师,则可以 简单 ...

  5. 我的Android进阶之旅】GitHub 上排名前 100 的 Android 开源库进行简单的介绍

    GitHub Android Libraries Top 100 简介 本文转载于:https://github.com/Freelander/Android_Data/blob/master/And ...

  6. 从http简介到网络分层及web架构

    浏览器发起HTTP请求的典型场景 a stateless application-level request/response protocol that uses extensible semant ...

  7. 可扩展的 Web 架构与分布式系统

    作者:Kate Matsudaira 译者:尹星 本文介绍了分布式架构是如何解决系统扩展性问题的粗略方法,适合刚刚入门分布式系统的同学,我把整篇文章翻译如下,希望给你一些启发. 备注:[idea]标注 ...

  8. C#中使用Socket实现简单Web服务器

    上一篇博客中介绍了怎样使用socket访问web服务器.关键有两个: 熟悉Socket编程: 熟悉HTTP协议. 上一篇主要是通过socket来模拟浏览器向(任何)Web服务器发送(HTTP)请求,重 ...

  9. 可扩展Web架构与分布式系统(转)

    1.1. web分布式系统的设计原则 搭建和运营一个可伸缩的web站点或者应用程序意味着什么?在原始层面上这仅仅是用户通过互联网连接到远程资源-使系统变得可伸缩的部分是将资源.或者访问的资源,分布于多 ...

随机推荐

  1. python 课堂笔记-while

    #Author:zyl age_of_oldboy = 56 count = 0 while count < 3: guess_age = int(input("guess age:& ...

  2. bind方法代替闭包

    <a href="JavaScript:">a</a> <a href="JavaScript:">b</a> ...

  3. Silverlight应用小知识点

    1 Silverlight目录下创建的类   与  根目录下创建的类:  是不同的:  Silverlight 不能调用根目录下的类:

  4. sql中null 和 ‘’(空字符串)

    sql 中 null  和 空字符串的区别方式 在Silverlight中  数据库 需要与实体类进行映射, 假如实体类不允许为null,则 select '' as 列名  from  表名字:   ...

  5. how to create an asp.net web api project in visual studio 2017

    https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/tutoria ...

  6. spark学习14(spark local模式运行spark程序的报错)

    报错1 java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries. 解 ...

  7. Map 的 key、value 是否允许为null

    Map的key和value是否允许null? 直接写程序验证一下: import java.util.HashMap; import java.util.Hashtable; import java. ...

  8. scala学习手记9 - =和==

    = 赋值运算 scala的赋值运算和java的有着很大的不同.如a=b这样的赋值运算,在Java中返回值是a的值,在scala中返回的则是Unit(Unit是值类型,全局只存在唯一的值,即(),通常U ...

  9. JNI_Z_05_方法的操作(没有String类型的参数)

    1.步骤: (1).获取 jclass (2).获取 method的id (3).调用 method ZC: 貌似 JNI里面 操作 类的方法,完全是 无视 访问权限的... 然而 static的方法 ...

  10. ImageView显示网络上的图片

    ImageView显示网络上的图片 一.简介 二.方法 1)ImageView显示网络上的图片方法 第一步:从网络上下载图片 byte[] byteArr = downImage();//这个是自己写 ...