from .inheritHandler import Base
from tornado.httpclient import AsyncHTTPClient, HTTPClientError
from tornado.web import StaticFileHandler, HTTPError
"""
该模块下包含一些基类,可以通过配置文件控制这些基类的反应行为
"""
[文档]class StaticHandler(StaticFileHandler, Base):
"""
继承 `StaticFileHandler` 和 `BaseHandler` ,用于处理静态文件访问控制的类,
"""
[文档] def initialize(self, path: str, default_filename: str = None, spa_page: str = None) -> None:
super(StaticHandler, self).initialize(path, default_filename)
self.absolute_path = path # 缺少这个属性web.py会报错,问题不大
self.spa_page = spa_page
# @override
[文档] async def get(self, path, include_body=True):
"""
默认等于StaticFileHandler.get()行为,通过写该方法,对文件进行控制,可以直接在这里编写代码
"""
if self.spa_page:
try:
await super(StaticHandler, self).get(path, include_body)
return
except HTTPError:
await super(StaticHandler, self).get(self.spa_page, include_body)
return
else:
await super(StaticHandler, self).get(path, include_body)
[文档]class ProxyHandler(Base):
"""
默认情况代理模块一定带有proxy前缀,可以在配置文件中更改proxy_prefix属性内容
代理服务采用流式请求远端服务器和流式返回内容的方式,即Transfer-Encoding: chunked
注意:代理请求根路径访问时结尾一定要加"/",如http://你的域名/proxy/bd/,否则不进行代理
在配置文件中,填写proxy_handler用来启用代理模块::
proxy_handler = [["p1","http://www.baidu.com"],["p2","http://www.google.com/"]]
上述配置了两个代理路由,访问URL如下:
1. 第一个:http://你的域名/proxy/p1/要访问的地址,这将代理到baidu下面
2. 第二个:http://你的域名/proxy/p2/要访问的地址,这将代理到google下面
proxy_prefix和alias(也就是配置中的p1或p2)可以为空,但是不能包含"/"
代理路径是 http://你的域名/proxy_prefix/alias/要访问的路径
.. attribute:: proxy_address
代理地址关键信息,包含{instead, address, host}
"""
def __init__(self, application, request, **kwargs):
super(ProxyHandler, self).__init__(application, request, **kwargs)
self.is_status = True
self.proxy_code = 200
self.__proxy_option = self.__proxy_option or None
# @override
[文档] def initialize(self, **kwargs):
"""
__init__之前回调的方法
:param kwargs: __proxy_address
:return: None
"""
self.__proxy_option = kwargs.get("proxy_option", None)
# @override
[文档] async def prepare(self):
"""
预处理回调,在请求开始之前执行的内容,设置允许跨域
:return: None
"""
await super(ProxyHandler, self).prepare()
self.set_access_headers()
# @override
[文档] async def options(self):
"""
符合下列条件,会跨域预检::
1. 请求方法不是GET/HEAD/POST
2. POST请求的Content-Type并非application/x-www-form-urlencoded, multipart/form-data, 或text/plain
3. 请求设置了自定义的header字段
:return: None
"""
self.set_access_headers()
# @override
[文档] async def get(self):
"""
GET方法请求代理
:return: None
"""
await self.proxy()
# @override
[文档] async def post(self):
"""
POST方法请求代理
:return: None
"""
await self.proxy()
# @override
[文档] async def put(self):
"""
PUT方法请求代理
:return: None
"""
await self.proxy()
# @override
[文档] async def delete(self):
"""
DELETE方法请求代理
:return: None
"""
await self.proxy()
[文档] def proxy_received_header(self, chunk):
"""
处理收到的头部信息
:param chunk: 收到的一行头部信息
:return: None
"""
if self.is_status:
self.is_status = False
self.proxy_code = int(chunk.split(" ")[1])
elif chunk == "\r\n":
self.set_status(self.proxy_code)
self.set_header("Proxy", "madtornado")
else:
if not next((code for code in [
"Transfer-Encoding",
"Content-Length",
"Server",
] if code in chunk), None):
if "Content-Type" in chunk:
self.set_header("Content-Type", chunk.split(":")[1].strip(" \r\n"))
else:
self._headers.parse_line(chunk)
[文档] def proxy_received_body(self, chunk):
"""
处理收到的body信息
:param chunk: 收到的body块
:return: None
"""
self.write(chunk)
self.flush()
[文档] async def proxy(self):
"""
访问代理::
http://域名/proxy/自定义后缀/代理的内容路径
:return: None
"""
if not self.__proxy_option:
self.throw(404)
return
opt = self.__proxy_option
req_uri = opt["address"] + self.request.uri.replace(opt["instead"], "")
body = self.request.body if self.request.body else None
method = self.request.method
headers = self.request.headers
headers["Host"] = opt["host"]
try:
await AsyncHTTPClient().fetch(req_uri, method=method, body=body, headers=headers,
validate_cert=False, request_timeout=10,
header_callback=self.proxy_received_header,
streaming_callback=self.proxy_received_body)
except HTTPClientError as e:
if e.code > 555:
self.throw(e.code)
[文档]class PongHandler(Base):
"""
有时可能需要测试服务器的服务是否启动,请访问/pong,来进行确定
"""
# @override
[文档] async def get(self):
"""
有时可能需要测试服务器的服务是否启动,请访问/pong,来进行确定
"""
self.throw(200, log_message="connected")
# @override
[文档] async def post(self):
"""
有时可能需要测试服务器的服务是否启动,请访问/pong,来进行确定
"""
await self.get()