浅析使用Python搭建http服务器


Posted in Python onOctober 27, 2019

David Wheeler有一句名言:“计算机科学中的任何问题,都可以通过加上另一层间接的中间层解决。”为了提高Python网络服务的可移植性,Python社区在PEP 333中提出了Web服务器网关接口(WSGI,Web Server Gateway Interface)。
为了提高Python网络服务的可移植性,Python社区在PEP 333中提出了Web服务器网关接口(WSGI,Web Server Gateway Interface)。

WSGL标准就是添加了一层中间层。通过这一个中间层,用Python编写的HTTP服务就能够与任何Web服务器进行交互了。现在,WSGI已经成为了使用Python进行HTTP操作的标准方法。

按照标准的定义,WSGI应用程序是可以被调用的,并且有两个输入参数。

1、WSGI

下面是第一段代码,第一个参数是environ,用于接收一个字典,字典中提供的键值对是旧式的CGI环境集合的拓展。第二个参数本身也是可以被调用的,习惯上会将其命名为start_response(),WSGI应用程序通过这个参数来声明响应头信息。

# 用WSGI应用形式编写的简单HTTP服务。
#!/usr/bin/env python3 
# A simple HTTP service built directly against the low-level WSGI spec. 
from pprint import pformat 
from wsgiref.simple_server import make_server 
def app(environ, start_response): 
 headers = {'Content-Type': 'text/plain; charset=utf-8'} 
 start_response('200 OK', list(headers.items())) 
 yield 'Here is the WSGI environment: 
'.encode('utf-8') 
 yield pformat(environ).encode('utf-8') 
if __name__ == '__main__': 
 httpd = make_server('', 8000, app) 
 host, port = httpd.socket.getsockname() 
 print('Serving on', host, 'port', port) 
 httpd.serve_forever()

上述只是一个简单的情况。但是在编写服务器程序时,复杂度就大大提升了。这是因为要完全考虑标准中的描述的许多注意点和边界情况。

2、前向代理与反向代理

无论前向代理还是反向代理,HTTP代理其实就是一个HTTP服务器,用于接收请求,然后对接收到的请求(至少是部分请求)进行转发。转发请求时代理会扮演客户端的角色,将转发的HTTP请求发送至真正的服务器,最后将从服务器接受到的响应发挥扮演客户端的角色,将转发的请求发送至真正的服务器,最后将从服务器接受到的响应发回给最初的客户端。
下面是前向代理和反向代理的简图。

浅析使用Python搭建http服务器

反向代理已经广泛应用于大型的HTTP服务当中。反向代理是Web服务的一部分,对于HTTP客户端并不可见。

3、四种架构

架构师一般都使用很多种复杂的机制来将多个子模块组合建成一个HTTP服务。现在在Python社区中,已经形成了4种基本的模式。如果已经编写了用于生成动态内容的Python代码,并且已经选择了某个支持WSGI的API或框架,应该如何将HTTP服务部署到线上呢?

运行一个使用Python编写的服务器,服务器的代码中可以直接调用WSGI接口。现在最流行的是Green Unicorn(Gunicorn)服务器,不过也有其他已经可以用于生产环境的纯Python服务器。

配置mod_wsgi并运行Apache,在一个独立的WSFIDaemonProcess中运行Python代码,由mod_wsgi启动守护进程。

在后端运行一个类似于Gunicorn的Python HTTP服务器(或者支持所选异步框架的任何服务器),然后在前端运行一个既能返回静态文件,又能对Python编写的动态资源服务进行反向代理的Web服务器。

在最前端运行一个纯粹的反向代理(如Varnish),在该反向代理后端运行Apache或者nginx,在后端运行Python编写的HTTP服务器。这是一个三层的架构。这些反向代理可以分布在不同的地理位置,这样子就能够将离客户端最近的反向代理上的缓存资源返回给发送请求的客户端。

浅析使用Python搭建http服务器

长期以来,对这4个架构的选择主要基于CPython的3个运行时的特性,即解释器占用内存大、解释器运行慢、全局解释器(GIL,Global Interpreter Lock)禁止多个线程同时运行Python字节码。但同时带来了内存中只能载入一定数量的Python实例。

4、平台即服务

这个概念的出现是因为现在的自动化部署、持续集成以及高性能大规模服务的相关技术的出现和处理有一些繁杂。所以有一些提供商提出了PaaS(Platform as a Service),现在只需关心应该如何打包自己的应用程序,以便将自己的应用部署到这些服务之上。
PaaS提供商会解决构建和运行HTTP服务中的出现的各种烦心事。不需要再关心服务器,或者是提供IP地址之类的事情。

PaaS会根据客户规模提供负载均衡器。只需要给PaaS提供商提供配置文件即可完成各种复杂的步骤。

现阶段比较常用的有Heroku和Docker。

大多数PaaS提供商不支持静态内容,除非我们在Python应用程序中实现了对静态内容的更多支持或者向容器中加入了Apache或ngnix。尽管我们可以将静态资源和动态页面的路径放在两个完全不同的URL空间内,但是许多架构师还是倾向于将两者放在同一个名字空间内。

5、不使用Web框架编写WSGI可调用对象

下面第一段代码是用于返回当前时间的原始WSGI可调用对象。

#!/usr/bin/env python3 
# A simple HTTP service built directly against the low-level WSGI spec. 
import time 
def app(environ, start_response): 
  host = environ.get('HTTP_HOST', '127.0.0.1') 
  path = environ.get('PATH_INFO', '/') 
  if ':' in host: 
    host, port = host.split(':', 1) 
  if '?' in path: 
    path, query = path.split('?', 1) 
  headers = [('Content-Type', 'text/plain; charset=utf-8')] 
  if environ['REQUEST_METHOD'] != 'GET': 
    start_response('01 Not Implemented', headers) 
    yield b'01 Not Implemented' 
  elif host != '127.0.0.1' or path != '/': 
    start_response('404 Not Found', headers) 
    yield b'404 Not Found' 
  else: 
    start_response('200 OK', headers) 
    yield time.ctime().encode('ascii')

第一段比较冗长。下面使用第三方库简化原始WGSI的模式方法。

第一个示例是使用WebOb编写的可调用对象返回当前时间。

#!/usr/bin/env python3 
# A WSGI callable built using webob. 
import time, webob 
def app(environ, start_response): 
  request = webob.Request(environ) 
  if environ['REQUEST_METHOD'] != 'GET': 
    response = webob.Response('501 Not Implemented', status=501) 
  elif request.domain != '127.0.0.1' or request.path != '/': 
    response = webob.Response('404 Not Found', status=404) 
  else: 
    response = webob.Response(time.ctime()) 
  return response(environ, start_response)

第二个是使用Werkzeug编写的WSGI可调用对象返回当前时间。

#!/usr/bin/env python3 
# A WSGI callable built using Werkzeug. 
import time 
from werkzeug.wrappers import Request, Response 
@Request.application 
def app(request): 
  host = request.host 
  if ':' in host: 
    host, port = host.split(':', 1) 
  if request.method != 'GET': 
    return Response('501 Not Implemented', status=501) 
  elif host != '127.0.0.1' or request.path != '/': 
    return Response('404 Not Found', status=404) 
  else: 
    return Response(time.ctime())

大家可以对比这两个库在简化操作时的不同之处,Werkzeug是Flask框架的基础。

总结

以上所述是小编给大家介绍的使用Python搭建http服务器,希望对大家有所帮助!

Python 相关文章推荐
linux系统使用python监控apache服务器进程脚本分享
Jan 15 Python
用Python编写一个每天都在系统下新建一个文件夹的脚本
May 04 Python
Python中处理字符串之endswith()方法的使用简介
May 18 Python
Python的Django应用程序解决AJAX跨域访问问题的方法
May 31 Python
Python入门_浅谈逻辑判断与运算符
May 16 Python
详解Python中for循环是如何工作的
Jun 30 Python
Python基于jieba库进行简单分词及词云功能实现方法
Jun 16 Python
Python获取网段内ping通IP的方法
Jan 31 Python
Python的缺点和劣势分析
Nov 19 Python
python 已知一个字符,在一个list中找出近似值或相似值实现模糊匹配
Feb 29 Python
python接口测试返回数据为字典取值方式
Feb 12 Python
Python保存并浏览用户的历史记录
Apr 29 Python
Python搭建代理IP池实现存储IP的方法
Oct 27 #Python
Python搭建代理IP池实现获取IP的方法
Oct 27 #Python
详解python statistics模块及函数用法
Oct 27 #Python
在 Jupyter 中重新导入特定的 Python 文件(场景分析)
Oct 27 #Python
python自动结束mysql慢查询会话的实例代码
Oct 27 #Python
python实现输入任意一个大写字母生成金字塔的示例
Oct 27 #Python
python 爬虫百度地图的信息界面的实现方法
Oct 27 #Python
You might like
php 修改、增加xml结点属性的实现代码
2013/10/22 PHP
php自定义函数br2nl实现将html中br换行符转换为文本输入中换行符的方法【与函数nl2br功能相反】
2017/02/17 PHP
Thinkphp5.0自动生成模块及目录的方法详解
2017/04/17 PHP
Laravel框架实现的批量删除功能示例
2019/01/16 PHP
JS date对象的减法处理实现代码
2010/12/28 Javascript
在JavaScript中监听IME键盘输入事件
2011/05/29 Javascript
JavaScript中数组的排序、乱序和搜索实现代码
2011/11/30 Javascript
自己编写的类似JS的trim方法
2013/10/09 Javascript
js实现在同一窗口浏览图片
2014/09/17 Javascript
浅谈javascript 归并方法
2015/01/21 Javascript
angularjs自定义ng-model标签的属性
2016/01/21 Javascript
浅谈jquery中next与siblings的区别
2016/10/27 Javascript
浅谈JavaScript的计时器对象
2016/12/26 Javascript
js实现固定宽高滑动轮播图效果
2017/01/13 Javascript
微信小程序 http请求的session管理
2017/06/07 Javascript
Object.keys() 和 Object.getOwnPropertyNames() 的区别详解
2020/05/21 Javascript
[03:30]DOTA2完美“圣”典精彩集锦
2016/12/27 DOTA
[01:20:05]DOTA2-DPC中国联赛 正赛 Ehome vs VG BO3 第二场 2月5日
2021/03/11 DOTA
跟老齐学Python之有容乃大的list(4)
2014/09/28 Python
极简的Python入门指引
2015/04/01 Python
python之PyMongo使用总结
2017/05/26 Python
Python数据结构之单链表详解
2017/09/12 Python
python的中异常处理机制
2018/08/30 Python
Python SMTP发送邮件遇到的一些问题及解决办法
2018/10/24 Python
Python 异常的捕获、异常的传递与主动抛出异常操作示例
2019/09/23 Python
python GUI框架pyqt5 对图片进行流式布局的方法(瀑布流flowlayout)
2020/03/12 Python
Python实现密钥密码(加解密)实例详解
2020/04/26 Python
python实现快速文件格式批量转换的方法
2020/10/16 Python
CSS3+HTML5+JS 实现一个块的收缩与展开动画效果
2020/11/17 HTML / CSS
Ootori在线按摩椅店:一家专业的按摩椅制造商
2019/04/10 全球购物
服装厂厂长岗位职责
2013/12/27 职场文书
前台文员个人求职信范文
2014/01/05 职场文书
学生请假条
2014/04/11 职场文书
2014学习优秀共产党员先进事迹材料思想汇报
2014/09/14 职场文书
大学生实训报告总结
2014/11/05 职场文书
如何使用PyCharm及常用配置详解
2021/06/03 Python