当成功建立好服务器后,接下来就是等待请求并处理请求通过路由分配给相应的视图函数了,以下是函数调用过程

-> self._handle_request_noblock()
/usr/lib/python2.7/SocketServer.py(295)_handle_request_noblock()
-> self.process_request(request, client_address)
/usr/lib/python2.7/SocketServer.py(321)process_request()
-> self.finish_request(request, client_address)
/usr/lib/python2.7/SocketServer.py(334)finish_request()
-> self.RequestHandlerClass(request, client_address, self)
/usr/lib/python2.7/SocketServer.py(649)__init__()
-> self.handle()
/home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/serving.py(217)handle()
-> rv = BaseHTTPRequestHandler.handle(self)
/usr/lib/python2.7/BaseHTTPServer.py(340)handle()
-> self.handle_one_request()
/home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/serving.py(252)handle_one_request()
-> return self.run_wsgi()
/home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/serving.py(194)run_wsgi()
-> execute(self.server.app)
/home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/serving.py(184)execute()
-> for data in application_iter:
/home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/debug/__init__.py(199)debug_application()

首先在刚建立的HTTPServer上会对发来的请求进行处理,得到请求的内容,headers,method等,并通过初始化HTTPBASERequestHandler将这些值都设为HTTPBASERequestHandler的属性。因为WSGIRequestHandler是继承HTTPBASERequestHandler的,所以他也可以使用这些属性来构建APP运行的environ。接着HTTPServer会调用handle方法,WSGIRequestHandler的源码如下

class WSGIRequestHandler(BaseHTTPRequestHandler, object):"""A request handler that implements WSGI dispatching."""@propertydef server_version(self):return 'Werkzeug/' + werkzeug.__version__def make_environ(self):request_url = url_parse(self.path)def shutdown_server():self.server.shutdown_signal = Trueurl_scheme = self.server.ssl_context is None and 'http' or 'https'path_info = url_unquote(request_url.path)environ = {'wsgi.version':         (1, 0),'wsgi.url_scheme':      url_scheme,'wsgi.input':           self.rfile,'wsgi.errors':          sys.stderr,'wsgi.multithread':     self.server.multithread,'wsgi.multiprocess':    self.server.multiprocess,'wsgi.run_once':        False,'werkzeug.server.shutdown': shutdown_server,'SERVER_SOFTWARE':      self.server_version,'REQUEST_METHOD':       self.command,'SCRIPT_NAME':          '','PATH_INFO':            wsgi_encoding_dance(path_info),'QUERY_STRING':         wsgi_encoding_dance(request_url.query),'CONTENT_TYPE':         self.headers.get('Content-Type', ''),'CONTENT_LENGTH':       self.headers.get('Content-Length', ''),'REMOTE_ADDR':          self.client_address[0],'REMOTE_PORT':          self.client_address[1],'SERVER_NAME':          self.server.server_address[0],'SERVER_PORT':          str(self.server.server_address[1]),'SERVER_PROTOCOL':      self.request_version}for key, value in self.headers.items():key = 'HTTP_' + key.upper().replace('-', '_')if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'):environ[key] = valueif request_url.netloc:environ['HTTP_HOST'] = request_url.netlocreturn environdef run_wsgi(self):if self.headers.get('Expect', '').lower().strip() == '100-continue':self.wfile.write(b'HTTP/1.1 100 Continue\r\n\r\n')self.environ = environ = self.make_environ()headers_set = []headers_sent = []def write(data):assert headers_set, 'write() before start_response'if not headers_sent:status, response_headers = headers_sent[:] = headers_settry:code, msg = status.split(None, 1)except ValueError:code, msg = status, ""self.send_response(int(code), msg)header_keys = set()for key, value in response_headers:self.send_header(key, value)key = key.lower()header_keys.add(key)if 'content-length' not in header_keys:self.close_connection = Trueself.send_header('Connection', 'close')if 'server' not in header_keys:self.send_header('Server', self.version_string())if 'date' not in header_keys:self.send_header('Date', self.date_time_string())self.end_headers()assert isinstance(data, bytes), 'applications must write bytes'self.wfile.write(data)self.wfile.flush()def start_response(status, response_headers, exc_info=None):if exc_info:try:if headers_sent:reraise(*exc_info)finally:exc_info = Noneelif headers_set:raise AssertionError('Headers already set')headers_set[:] = [status, response_headers]return writedef execute(app):application_iter = app(environ, start_response)try:for data in application_iter:write(data)if not headers_sent:write(b'')finally:if hasattr(application_iter, 'close'):application_iter.close()application_iter = Nonetry:execute(self.server.app)except (socket.error, socket.timeout) as e:self.connection_dropped(e, environ)except Exception:if self.server.passthrough_errors:raisefrom werkzeug.debug.tbtools import get_current_tracebacktraceback = get_current_traceback(ignore_system_exceptions=True)try:# if we haven't yet sent the headers but they are set# we roll back to be able to set them again.if not headers_sent:del headers_set[:]execute(InternalServerError())except Exception:passself.server.log('error', 'Error on request:\n%s',traceback.plaintext)def handle(self):"""Handles a request ignoring dropped connections."""rv = Nonetry:rv = BaseHTTPRequestHandler.handle(self)except (socket.error, socket.timeout) as e:self.connection_dropped(e)except Exception:if self.server.ssl_context is None or not is_ssl_error():raiseif self.server.shutdown_signal:self.initiate_shutdown()return rvdef initiate_shutdown(self):"""A horrible, horrible way to kill the server for Python 2.6 andlater.  It's the best we can do."""# Windows does not provide SIGKILL, go with SIGTERM then.sig = getattr(signal, 'SIGKILL', signal.SIGTERM)# reloader activeif os.environ.get('WERKZEUG_RUN_MAIN') == 'true':os.kill(os.getpid(), sig)# python 2.7self.server._BaseServer__shutdown_request = True# python 2.6self.server._BaseServer__serving = Falsedef connection_dropped(self, error, environ=None):"""Called if the connection was closed by the client.  By defaultnothing happens."""def handle_one_request(self):"""Handle a single HTTP request."""self.raw_requestline = self.rfile.readline()if not self.raw_requestline:self.close_connection = 1elif self.parse_request():return self.run_wsgi()def send_response(self, code, message=None):"""Send the response header and log the response code."""self.log_request(code)if message is None:message = code in self.responses and self.responses[code][0] or ''if self.request_version != 'HTTP/0.9':hdr = "%s %d %s\r\n" % (self.protocol_version, code, message)self.wfile.write(hdr.encode('ascii'))def version_string(self):return BaseHTTPRequestHandler.version_string(self).strip()def address_string(self):return self.environ['REMOTE_ADDR']def log_request(self, code='-', size='-'):self.log('info', '"%s" %s %s', self.requestline, code, size)def log_error(self, *args):self.log('error', *args)def log_message(self, format, *args):self.log('info', format, *args)def log(self, type, message, *args):_log(type, '%s - - [%s] %s\n' % (self.address_string(),self.log_date_time_string(),message % args))

在其中的handle方法会包装了BASERequestHandler的handle方法,如果socket出现错误或超时,它会继续尝试链接,initiate_shutdown是当收到关闭信号时,将服务器强制关闭,这个handle方法在官方文档描述会返回handle_one_request方法,他得到一个HTTP请求,并调用run_wsgi方法进行处理,在run_wsgi中,先将先前设为类属性的Request环境变量储存在environ字典中。这是WSGI的规范,服务器要向app提供environ和start_response两个参数,start_response方法会设置status和reponse_headers,具体可看PEP333规范。然后,会尝试运行excute,如果发生了除socket.error或socket.timeout之外的错误,在debug模式下会返回调试页面。

再接下来的excute函数中,他调用APP并传递environ和start_response两个参数,根据WSGI规范,它应该得到可迭代的对象,然后就调用write将这些数据写出去。在write方法中,他会首先确定start_response先被调用,首先若还没有发送headers,会先将headers_set中的status以及response_header发送出去,之后再将得到的数据发送出去,这样,服务器端的任务基本就完成了。

转载于:https://www.cnblogs.com/steinliber/p/5133386.html

werkzeug中服务器处理请求的实现相关推荐

  1. java中使用ajax请求数据格式化,ajax请求服务器返回json数据格式化

    JQuery--实现Ajax应用 实现Ajax应用 1   .load()异步请求数据,通过Ajax请求加载服务器中的数据,并把返回的数据放置到指定的元素中,调用格式为load(url,[data], ...

  2. 请求一次服务器会显示请求了两次,在Appengin中,每个请求都会到达服务器两次...

    我在appengine有一个小应用程序.在我的本地开发服务器中,每个请求都会访问服务器两次. 在调试模式下,我可以看到get方法调用了两次. 这在chrome和firefox浏览器中都会发生. 这是本 ...

  3. .net中对HTTP请求的两种请求:Get和Post的操作

    .net中对HTTP请求的简单操作总结 第一部分,HTTP协议的简单了解 一.           什么是HTTP协议 超文本传输协议 (HTTP-Hypertext transfer protoco ...

  4. HTTP协议---HTTP请求中的常用请求字段和HTTP的响应状态码及响应头

    http://blog.csdn.net/qxs965266509/article/details/8082810 用于HTTP请求中的常用请求头字段 Accept:用于高速服务器,客户机支持的数据类 ...

  5. 【Netty】使用 Netty 开发 HTTP 服务器 ( HTTP 请求过滤 )

    文章目录 一. HTTP 服务器请求过滤功能 1 . HTTP 服务器资源请求过滤 2 . HTTP 请求过滤方法 二. HTTP 服务器 ( 资源过滤 ) 代码实现 1 . 服务器主程序 2 . 服 ...

  6. ASP.NET中处理HTTP请求的原理 (转)

    ASP.Net产生的大背景: 在Internet时代的开端,客户端的需求非常有限:.htm文件就可以满足他们的需求.但是,随着时间的流逝,客户端需求的扩充超越了.htm文件或静态文件所包含的功能. 开 ...

  7. openresty开发系列29--openresty中发起http请求

    openresty开发系列29--openresty中发起http请求 有些场景是需要nginx在进行请求转发 用户浏览器请求url访问到nginx服务器,但此请求业务需要再次请求其他业务: 如用户请 ...

  8. [转]android之Apache Http——向服务器发送请求的同时发送参数

    android之Apache Http--向服务器发送请求的同时发送参数 使用Get方法提交: 其他步骤与上一节的操作相符,只是在传送地址的时候发送参数的格式如下: //Sname和Sage是实际的数 ...

  9. android处理服务器的集合,android集合SSH搭建服务器客户端请求

    android集合SSH搭建服务器客户端请求 (2012-06-14 06:21:53) 标签: android 服务器 杂谈 android集合SSH搭建服务器客户端请求小弟以前是学的J2EE,由于 ...

最新文章

  1. Laravel7使用Auth进行用户认证
  2. shell 中柏开机显示efi_中柏 ezpad 平板安装Fedora 21 (Linux)
  3. 网络性能测试工具Iperf上手指南
  4. MCtalk 创业声音丨辉禹科技合伙人孔杰:投资和创业都是思维的放大器
  5. liferay mysql driver_Liferay更改数据库(oracle,mysql)
  6. 索引扫描时,对同一个叶子块访问多次的原因初探
  7. PureCode--iOS--自定义UITableViewCell(含疑问)
  8. 03-肯德基点餐:抽象工厂模式
  9. 哟,2020 年了,用 Vue 做一个自己的小程序吧!| 原力计划
  10. Istio 核心组件介绍
  11. C#中的线程二(BeginInvoke和Invoke)
  12. OMRON PLC使用技巧总结
  13. 继微信dat之后的PC端微信解密后数据库数据抽取
  14. Hiren’s BootCD 15.2下载 – 史上最强大的WinPE U盘启动工具详细介绍
  15. 企业运用通兑吧数字会员卡进行营销的优势
  16. 我也来开发2048之确定思路
  17. C# 下拉菜单的设置 lookupedit
  18. A Primer on Memory Consistency and Cache Coherence—第五章 Relaxed Memory Model
  19. Cobaltstrike系列教程(十一)提权与横向移动
  20. electron 文件另存为

热门文章

  1. spark-submit参数说明--on YARN
  2. 在eclipse使用map reduce编写word count程序生成jar包并在虚拟机运行的步骤
  3. Luogu5369 [PKUSC2018]最大前缀和
  4. 以太坊开发(二)使用Ganache CLI在私有链上搭建智能合约
  5. python基础回顾
  6. Python:变量与字符串
  7. sql 日期概念理解中的一些测试
  8. ArcGIS 坐标系统文件
  9. 查看mysql版本不一致_MySQL-版本不一致
  10. springboot 引入jdbc驱动_SpringBoot整合jdbc、durid、mybatis详解,数据库的连接就是这么简单...