更新时间:2019年07月26日 10时48分13秒 来源:黑马程序员论坛
简介 Python Web开发中,后台服务端程序可以分为两个部分,1.是服务器程序 2.是应用程序.服务器通常是TCP服务器,负责处理来自客户端(一般都是浏览器/APP)请求的整理/分发/响应.2.后者负责具体的逻辑处理.这时候为了方便应用程序的开发,我们把常用的功能封装起来,成为各种Web开发框架,Django/Flask/Tornado.不同的框架有不同的开发方式,但是开发出来的应用程序都需要和服务器程序配合,才能算是完整的后台服务. 如果服务器程序和应用程序之间没有标准的协议,我们在开发一套应用程序的时候是不是要针对某个具体的服务器程序来写,而不能随便来写.这时候我们就需要规定出一套特定协议,将应用程序和服务器程序解耦出来.而 WSGI就是这个作用.Python Web开发中,这套标准协议就是 The Web Server Gateway Interface,即 WSGI,这套标准在官方的 PEP 333中描述. WSGI是服务器程序与应用程序的一个约定,它规定了双方各自需要实现什么接口,提供了什么功能,以便二者能够配合使用.WSGI 不能规定的太复杂,否则对已有的服务器来说,实现起来会困难,不利于WSGI的普及。同时WSGI也不能规定的太多,例如cookie处理就没有在WSGI中规定,这是为了给框架最大的灵活性。要知道WSGI最终的目的是为了方便服务器与应用程序配合使用,而不是成为一个Web框架的标准。 WSGI-应用程序 WSGI规定:
我们看下官方文档给出的定义 [Python] 纯文本查看 复制代码 HELLO_WORLD = b"Hello world!\n" # callable function def simple_app(environ, start_response): """Simplest possible application object""" status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return [HELLO_WORLD] # callable class class AppClass: """Produce the same output, but using a class (Note: 'AppClass' is the "application" here, so calling it returns an instance of 'AppClass', which is then the iterable return value of the "application callable" as required by the spec. If we wanted to use *instances* of 'AppClass' as application objects instead, we would have to implement a '__call__' method, which would be invoked to execute the application, and we would need to create an instance for use by the server or gateway. """ def __init__(self, environ, start_response): self.environ = environ self.start = start_response def __iter__(self): status = '200 OK' response_headers = [('Content-type', 'text/plain')] self.start(status, response_headers) yield HELLO_WORLD # callable object class ApplicationObj(object): def __call__(self, environ, start_response): return [HELL_WORLD] 翻译过来就是:
同时, WSGI规定
这时候了解Python Web开发的可能就会讲了,平时我们写的应用程序并不是这个样子的,应该是下面这种 [Python] 纯文本查看 复制代码 class Index(View): def get(self): return 'Hello world' 这是因为框架已经帮我们把WSGI规定的一些东西封装起来,我们平时用框架时看不到,只需要直接实现我们的逻辑,再返回一个值就好了。其它的东西框架帮我们做好了。这也是框架的价值所在,把常用的东西封装起来,让使用者只需要关注最重要的东西。 比如 Django框架的 WSGI Application 就采用的 callable object的形式 [Python] 纯文本查看 复制代码 # lib/python3.7/site-packages/django/core/handlers/wsgi.py 146 line class WSGIHandler(base.BaseHandler): request_class = WSGIRequest def __init__(self, *args, **kwargs): super(WSGIHandler, self).__init__(*args, **kwargs) self.load_middleware() def __call__(self, environ, start_response): set_script_prefix(get_script_name(environ)) signals.request_started.send(sender=self.__class__, environ=environ) request = self.request_class(environ) response = self.get_response(request) response._handler_class = self.__class__ status = '%d %s' % (response.status_code, response.reason_phrase) response_headers = [(str(k), str(v)) for k, v in response.items()] for c in response.cookies.values(): response_headers.append((str('Set-Cookie'), str(c.output(header='')))) start_response(force_str(status), response_headers) if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'): response = environ['wsgi.file_wrapper'](response.file_to_stream) return response 服务器程序会在每次客户端的请求传来时,调用我们写好的应用程序,并将处理好的结果(response)返回客户端.
服务器程序大概是这个样子 [Python] 纯文本查看 复制代码 # 具体见PEP333规范 def run_with_cgi(application): environ = {} def write(data): pass def start_response(status, response_headers, exc_info=None): pass # 调用应用程序 result = application(environ, start_response) try: for data in result: if data: # don't send headers until body appears write(data) if not headers_sent: write('') # send headers now if body was empty finally: if hasattr(result, 'close'): result.close() 这里可以看出服务器程序是如何与应用程序配合完成用户请求的。 WSGI规定了应用程序需要一个可调用对象,有两个参数,返回一个可迭代对象。在服务器 程序中,针对这几个规定,做了以下几件事:
有些功能可能介于服务器程序和应用程序之间,例如,服务器拿到了客户端请求的URL, 不同的URL需要交由不同的函数处理,这个功能叫做 URL Routing,这个功能就可以放在二者中间实现,这个中间层就是 middleware。 有点类似于语法糖 装饰器, [Python] 纯文本查看 复制代码 # URL Routing middleware def urlrouting(url_app_mapping): def midware_app(environ, start_response): url = environ['PATH_INFO'] app = url_app_mapping[url] result = app(environ, start_response) return result return midware_app ''' 中间件作用说明: 服务器拿到了客户端请求的URL, 不同的URL需要交由不同的函数处理,这个功能叫做 URL Routing,这个功能就可以放在二者中间实现,这个中间层就是 middleware。 ''' 应用程序
[Python] 纯文本查看 复制代码 # server programmed def run(application): environ = {} # set environ def write(data): pass def start_response(status, response_headers, exc_info=None): return write try: result = application(environ, start_response) finally: if hasattr(result, 'close'): result.close() if hasattr(result, '__len__'): # result must be accumulated pass for data in result: write(data) HELLO_WORLD = b"Hello world!\n" # callable function def application(environ, start_response): status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return [HELLO_WORLD] environ变量 environ 变量需要包含 CGI 环境变量,它们在The Common Gateway Interface Specification 中定义,下面列出的变量必须包含在 enciron变量中:
[Python] 纯文本查看 复制代码 REQUEST_METHOD = 'GET' SCRIPT_NAME = '' PATH_INFO = '/xyz' QUERY_STRING = 'abc' CONTENT_TYPE = 'text/plain' CONTENT_LENGTH = '' SERVER_NAME = 'minix-ubuntu-desktop' SERVER_PORT = '8000' SERVER_PROTOCOL = 'HTTP/1.1' HTTP_ACCEPT = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' HTTP_ACCEPT_ENCODING = 'gzip,deflate,sdch' HTTP_ACCEPT_LANGUAGE = 'en-US,en;q=0.8,zh;q=0.6,zh-CN;q=0.4,zh-TW;q=0.2' HTTP_CONNECTION = 'keep-alive' HTTP_HOST = 'localhost:8000' HTTP_USER_AGENT = 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36' Unicode HTTP 不支持 Unicode, 所有编码/解码都必须由应用程序完成,所有传递给或者来自server的字符串都必须是 str 或者bytes类型,而不是unicode。 注意:WSGI中的 bytestrings在Python3中指 bytes,在Python2中指 str |
推荐了解热门学科
java培训 | Python人工智能 | Web前端培训 | PHP培训 |
区块链培训 | 影视制作培训 | C++培训 | 产品经理培训 |
UI设计培训 | 新媒体培训 | 产品经理培训 | Linux运维 |
大数据培训 | 智能机器人软件开发 |
传智播客是一家致力于培养高素质软件开发人才的科技公司,“黑马程序员”是传智播客旗下高端IT教育品牌。自“黑马程序员”成立以来,教学研发团队一直致力于打造精品课程资源,不断在产、学、研3个层面创新自己的执教理念与教学方针,并集中“黑马程序员”的优势力量,针对性地出版了计算机系列教材50多册,制作教学视频数+套,发表各类技术文章数百篇。
传智播客从未停止思考
传智播客副总裁毕向东在2019IT培训行业变革大会提到,“传智播客意识到企业的用人需求已经从初级程序员升级到中高级程序员,具备多领域、多行业项目经验的人才成为企业用人的首选。”
中级程序员和初级程序员的差别在哪里?
项目经验。毕向东表示,“中级程序员和初级程序员最大的差别在于中级程序员比初级程序员多了三四年的工作经验,从而多出了更多的项目经验。“为此,传智播客研究院引进曾在知名IT企业如阿里、IBM就职的高级技术专家,集中研发面向中高级程序员的课程,用以满足企业用人需求,尽快补全IT行业所需的人才缺口。
何为中高级程序员课程?
传智播客进行了定义。中高级程序员课程,是在当前主流的初级程序员课程的基础上,增加多领域多行业的含金量项目,从技术的广度和深度上进行拓展。“我们希望用5年的时间,打造上百个高含金量的项目,覆盖主流的32个行业。”传智播客课程研发总监于洋表示。
黑马程序员热门视频教程【点击播放】
Python入门教程完整版(懂中文就能学会) | 零起点打开Java世界的大门 |
C++| 匠心之作 从0到1入门学编程 | PHP|零基础入门开发者编程核心技术 |
Web前端入门教程_Web前端html+css+JavaScript | 软件测试入门到精通 |