当前位置: 首页 > 科技观察

Python中的HTTP服务器

时间:2023-03-14 10:40:16 科技观察

DavidWheeler有一句名言:“计算机科学中的任何问题都可以通过添加另一层间接中间层来解决。”为了提高Python网络服务的可移植性,Python社区在PEP333中提出了Web服务器网关接口(WSGI,WebServerGatewayInterface)。WSGL标准增加了一个中间层。通过这个中间层,用Python编写的HTTP服务可以与任何Web服务器进行交互。今天,WSGI已经成为用Python进行HTTP操作的标准方式。根据标准定义,可以使用两个输入参数调用WSGI应用程序。1、以下是WSGI中的第一段代码。第一个参数是environ,用于接收字典。字典中提供的键值对是旧CGI环境集合的扩展。第二个参数本身也可以调用,习惯上将其命名为start_response(),WSGI应用通过该参数声明响应头信息。#以WSGI应用形式编写的简单HTTP服务。#!/usr/bin/envpython3#AsimpleHTTPservicebuiltdirectlyagainstthelow-levelWSGIspec.frompprintimportpformatfromwsgiref.simple_serverimportmake_serverdefapp(environ,start_response):headers={'Content-Type':'text/plain;charset=utf-8'}start_response('200OK',列表(headers.items()))yield'HereistheWSGIenvironment:'.encode('utf-8')yieldpformat(environ).encode('utf-8')if__name__=='__main__':httpd=make_server('',8000,app)host,port=httpd.socket.getsockname()print('Servingon',host,'port',port)httpd.serve_forever()以上只是一个简单的案例。但是在写服务器程序的时候,复杂度就大大提高了。这是由于要充分考虑标准中描述的许多注意事项和边缘情况。2、正向代理和反向代理不管是正向代理还是反向代理,HTTP代理实际上就是一个HTTP服务器,负责接收请求,然后转发接收到的请求(至少是部分请求)。在转发请求时,代理会扮演客户端的角色,将转发的HTTP请求发送给真实的服务器,最后扮演客户端的角色,将转发的请求发送给真实的服务器,并最终收到服务器的响应,将响应发送回原来的客户端。下面是正向代理和反向代理的简化图。反向代理在大型HTTP服务中得到了广泛的应用。反向代理是Web服务的一部分,对HTTP客户端不可见。3.四种架构架构师一般会使用很多复杂的机制将多个子模块组合成一个HTTP服务。现在在Python社区中,已经形成了四种基本模式。如果你已经编写过生成动态内容的Python代码,并且选择了支持WSGI的API或框架,那么应该如何在线部署HTTP服务呢?运行一个用Python编写的服务器,服务器代码可以直接调用WSGI接口。最受欢迎的是GreenUnicorn(Gunicorn)服务器,但还有其他可用于生产的纯Python服务器。配置mod_wsgi并运行Apache,在单独的WSFIDaemonProcess中运行Python代码,并使用mod_wsgi启动守护进程。在后端运行一个类似Gunicorn的PythonHTTP服务器(或任何支持所选异步框架的服务器),然后在前端运行一个Web服务器,它返回静态文件,反向代理服务于用Python服务器编写的动态资源。前端运行纯反向代理(如Varnish),反向代理后端运行Apache或nginx,后端运行Python编写的HTTP服务器。这是一个三层架构。这些反向代理可以分布在不同的地理位置,这样就可以将离客户端最近的反向代理上的缓存资源返回给发送请求的客户端。一直以来,这四种架构的选择主要是基于CPython的三大运行时特性,即解释器占用内存大、解释器运行缓慢、全局解释器(GIL,GlobalInterpreterLock)禁止多重同时运行Python的线程。字节码。但同时带来的是内存中只能加载一定数量的Python实例。4、平台即服务概念的出现,是由于自动化部署、持续集成、高性能大规模服务相关技术的复杂出现和处理。所以一些提供商提出了PaaS(PlatformasaService),现在他们只需要关心如何打包自己的应用,以便部署在这些服务上即可。PaaS提供商负责解决构建和运行HTTP服务的痛点。您不再需要关心服务器,也不需要提供IP地址之类的东西。PaaS会根据客户的规模提供负载均衡器。您只需向PaaS提供商提供配置文件,即可完成各种复杂的步骤。现阶段比较常用的是Heroku和Docker。大多数PaaS提供商不支持静态内容,除非我们在Python应用程序中实现更多对静态内容的支持,或者将Apache或ngnix添加到容器中。虽然我们可以将静态资源和动态页面的路径放在两个完全不同的URL空间中,但是很多架构师更喜欢将两者放在同一个命名空间中。5.在不使用网络框架的情况下编写一个WSGI可调用对象。下面的第一段代码是用于返回当前时间的原始WSGI可调用对象。#!/usr/bin/envpython3#AsimpleHTTPservicebuiltdirectlyagainstthelow-levelWSGIspec.importtimedefapp(environ,start_response):host=environ.get('HTTP_HOST','127.0.0.1')path=environ.get('PATH_INFO','/')if':'inhost:host,port=host.split(':',1)if'?'inpath:path,query=path.split('?',1)headers=[('Content-Type','text/plain;charset=utf-8')]ifenviron['REQUEST_METHOD']!='GET':start_response('501NotImplemented',headers)yieldb'501NotImplemented'elifhost!='127.0.0.1'orpath!='/':start_response('404NotFound',headers)yieldb'404NotFound'else:start_response('200OK',headers)yieldtime.ctime().encode('ascii')第一段相当长。下面使用第三方库简化原WGSI的schema方法。第一个示例是使用返回当前时间的WebOb编写的可调用对象。#!/usr/bin/envpython3#AWSGIcallablebuiltusingwebob.importtime,webobdefapp(environ,start_response):request=webob.Request(environ)ifenviron['REQUEST_METHOD']!='GET':response=webob.Response('501NotImplemented',status=501)elifrequest.domain!='127.0.0.1'orrequest.path!='/':response=webob.Response('404NotFound',status=404)else:response=webob.Response(time.ctime())returnresponse(environ,start_response)第二种是使用Werkzeug写的WSGI可调用对象返回当前时间。第二种是使用Werkzeug编写的WSGI可调用函数返回当前时间。#!/usr/bin/envpython3#AWSGIcallablebuiltusingWerkzeug.importtimefromwerkzeug.wrappersimportRequest,Response@Request.applicationdefapp(request):host=request.hostif':'inhost:host,port=host.split(':',1)ifrequest。method!='GET':returnResponse('501NotImplemented',status=501)elifhost!='127.0.0.1'orrequest.path!='/':returnResponse('404NotFound',status=404)else:returnResponse(time.ctime())可以比较一下这两个库在简化操作上的区别。Werkzeug是Fl??ask框架的基础。