werkzeug中服务器处理请求的实现
当成功建立好服务器后,接下来就是等待请求并处理请求通过路由分配给相应的视图函数了,以下是函数调用过程
-> 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.""" @property
def server_version(self):
return 'Werkzeug/' + werkzeug.__version__ def make_environ(self):
request_url = url_parse(self.path) def shutdown_server():
self.server.shutdown_signal = True url_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] = value if request_url.netloc:
environ['HTTP_HOST'] = request_url.netloc return environ def 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_set
try:
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 = True
self.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 = None
elif headers_set:
raise AssertionError('Headers already set')
headers_set[:] = [status, response_headers]
return write def 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 = None try:
execute(self.server.app)
except (socket.error, socket.timeout) as e:
self.connection_dropped(e, environ)
except Exception:
if self.server.passthrough_errors:
raise
from werkzeug.debug.tbtools import get_current_traceback
traceback = 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:
pass
self.server.log('error', 'Error on request:\n%s',
traceback.plaintext) def handle(self):
"""Handles a request ignoring dropped connections."""
rv = None
try:
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():
raise
if self.server.shutdown_signal:
self.initiate_shutdown()
return rv def initiate_shutdown(self):
"""A horrible, horrible way to kill the server for Python 2.6 and
later. It's the best we can do.
"""
# Windows does not provide SIGKILL, go with SIGTERM then.
sig = getattr(signal, 'SIGKILL', signal.SIGTERM)
# reloader active
if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
os.kill(os.getpid(), sig)
# python 2.7
self.server._BaseServer__shutdown_request = True
# python 2.6
self.server._BaseServer__serving = False def connection_dropped(self, error, environ=None):
"""Called if the connection was closed by the client. By default
nothing 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 = 1
elif 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发送出去,之后再将得到的数据发送出去,这样,服务器端的任务基本就完成了。
werkzeug中服务器处理请求的实现的更多相关文章
- C#中使用Socket请求Web服务器过程
最开始我们需要明白一件事情,因为这是这篇文章的前提: HTTP协议只是一个应用层协议,它底层是通过TCP进行传输数据的.因此,浏览器访问Web服务器的过程必须先有“连接建立”的发生. 而有人或许会问: ...
- [转] c# 模拟Asp.net页面中的某个按钮的点击,向web服务器发出请求
在没有做题目中所述的内容的时候,感觉这应该是很简单的东西,但是当真正开始做的时候却发现,有很多问题现在在这里写出来,供和我一样水平不高的参考一下. 在写本文之前参照了一下文章 欢迎使用CSDN论坛阅读 ...
- ajax-向服务器发送请求
ajax-向服务器发送请求 1.将请求发送到服务器,使用XMLHttpRequest对象的 open() 和 send() 方法. xmlhttp. open(method,url,async ...
- HTTP协议---HTTP请求中的常用请求字段和HTTP的响应状态码及响应头
http://blog.csdn.net/qxs965266509/article/details/8082810 用于HTTP请求中的常用请求头字段 Accept:用于高速服务器,客户机支持的数据类 ...
- javascrpt 中的Ajax请求
回顾下javascript中的Ajax请求,写一个小例子: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN& ...
- android中用get和post方式向服务器提交请求
通过get和post方式向服务器发送请求首先说一下get和post的区别get请求方式是将提交的参数拼接在url地址后面,例如http://www.baidu.com/index.jsp?num=23 ...
- ASP.NET Core Razor中处理Ajax请求
如何ASP.NET Core Razor中处理Ajax请求 在ASP.NET Core Razor(以下简称Razor)刚出来的时候,看了一下官方的文档,一直没怎么用过.今天闲来无事,准备用Rozor ...
- for循环中进行联网请求数据、for循环中进行异步数据操作,数据排序错乱问题解决;
for循环中进行联网请求数据,由于网络请求是异步的,第一个网络请求还没有回调,第二次第三次以及后续的网络请求又已经发出去了,有可能后续的网络请求会先回调:这时我们接收到的数据的排序就会错乱:怎么才能让 ...
- (转)在.net中检索HTTP请求
原文转载:https://www.west-wind.com/presentations/dotnetWebRequest/dotnetWebRequest.htm HTTP内容检索是应用程序的重要组 ...
随机推荐
- Azure 网站和通配符域
本文章由Azure 网站团队软件开发工程师Michael Candido 撰写 一些 Web 应用程序需要使用多个子域,在某些情况下还需要动态添加新的子域.例如,一个多租户 Web 应用程序可使 ...
- VM Agent 和扩展程序
VM Agent 和扩展程序 - 第 1 部分 Windows Azure基础结构服务最近宣布了一项新功能VM Agent.VMAgent是一个轻量级进程,用于启动由Microsoft或合作伙伴 ...
- 掌握下面常用函数,学php不再难
一.写入文件 1.打开资源(文件)fopen($filename,$mode) 2.写文件fwrite($handle,$str) 3.关闭文件fclose($handle) 4.一步写入file_p ...
- 网页解析不了PHP源代码的解决方法
一般出现这个错误都是因为修改了apache配置文件,但是没有使apache配置生效. 所以只要执行以下命令就行了: sudo apachectl restart sudo apachectl grac ...
- Good Luck in CET-4 Everybody!(博弈)
Good Luck in CET-4 Everybody! Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K ...
- C++学习笔记6
泛型算法 1. 算法怎样工作 每一个泛型算法的实现都独立于单独的容器.这些算法还是大而不全的,而且不依赖于容器存储的元素类型.为了知道算法怎样工作,让我们深入了解find 操作.该操作的任务是在一个未 ...
- 使用COCOS2D-X JSB开发,在js页面中设置iOS键盘模式
XYSDK.h void setKeyboardType(int type); XYSDK.cpp voidXYSDK::setKeyboardType(int type) { #if (CC_TAR ...
- c/c++测试程序运行时间
算法分析中需要对各种算法进行性能测试,下面介绍两种通用的测试方法,由于只用到标准c语言函数,所以在各种平台和编译器下都能使用. 方法1: clock()函数 开始计时:start = clock() ...
- 如何最简单的优化MySql
1.创建索引,一定要根据实际情况来创建,如果是连接表查询,如一个主帐号连接多个子帐号,可以考虑两个或三个以上的多索引: 2.合理利用时间排序,由于大多数表格用时间来排序,数据量相当大的时候,在时间列上 ...
- Vijos 1083 小白逛公园(线段树)
线段树,每个结点维护区间内的最大值M,和sum,最大前缀和lm,最大后缀和rm. 若要求区间为[a,b],则答案max(此区间M,左儿子M,右儿子M,左儿子rm+右儿子lm). ----------- ...