def generate_proxy_HTTPRequest(self, **kwargs) -> HTTPClientRequest: request_obj: HTTPServerRequest = self.request protocol = kwargs.pop('protocol', request_obj.protocol) server = kwargs.pop('host', kwargs.pop('server', request_obj.host)) uri = kwargs.pop('uri', request_obj.uri) new_url = kwargs.pop('url', f"{protocol}://{server}{uri}") _headers = HTTPHeaders(kwargs.pop('headers', request_obj.headers)) _headers['Connection'] = 'keep-alive' _headers.pop('Host', None) _method = kwargs.pop('method', request_obj.method).upper() _body = kwargs.pop('body', request_obj.body) _headers.pop('Transfer-Encoding', None) if (_body): _headers['Content-Length'] = str(len(_body)) else: _headers.pop('Content-Length', None) _allow_nonstandard_methods = kwargs.pop('allow_nonstandard_methods', True) _proxy_request = HTTPClientRequest(url=new_url, method=_method, body=_body, headers=_headers, allow_nonstandard_methods=_allow_nonstandard_methods, **kwargs) return _proxy_request
class GatewayApi(tornado.websocket.WebSocketHandler): # 针对websocket请求, 接收消息 async def on_message(self, message): if self._up_websocket is not None: # 将接收到的消息发送给upstream websocket await self._up_websocket.send(message) # 针对websocket请求断开连接时处理, 因为tornado的实现, 这个方法不能声明为异步的 def on_ws_connection_close(self, close_code: int = None, close_reason: str = None): if self._up_websocket is not None and self._up_websocket.closed is False: import tornado.ioloop # 因为up_websocket.close是异步的,需要启动一个task来执行 io_loop = tornado.ioloop.IOLoop.current() io_loop.spawn_callback(self._up_websocket.close) super().on_ws_connection_close() async def get(self, *args, **kwargs): # 判断请求是否是通过HTTP进行Upgrade的websocket if self.request.headers.get("Upgrade", "").lower() == "websocket": # 调用相应的app_core来获取代理的upstream上游的websocket connection, 建立上游连接 self._up_websocket = await g.app_core.get_up_websocket( self.request, self) # 调用父类的get的方法处理websocket请求, 产生响应 await super().get(*args, **kwargs) else: # 其他HTTP web请求按照正常逻辑处理 output = {'result': {}, 'finish': False} thread = threading.Thread(target=gateway_service, args=(self.request, output)) thread.setDaemon(True) thread.start() while not output['finish']: await asyncio.sleep(0.01) result = output['result'] if result['status'] == 'ok': new_access_token = result['value'].get( 'new_access_token') # 用 get 而不是 [] 来取值,因为可能不存在 new_refresh_token = result['value'].get('new_refresh_token') response = result['value']['response'] if new_access_token is not None and new_refresh_token is not None: self.set_cookie('access_token', new_access_token) self.set_cookie('refresh_token', new_refresh_token) self.set_status(response.status_code) self._headers = HTTPHeaders(response.headers) # 注意:需要强制类型转换 if self._headers.get('Content-Type') == 'gzip': try: self._headers.pop('Content-Type') self._headers.pop('Content-Length') except: pass if self.request.headers.get('Origin'): self.set_header('Access-Control-Allow-Credentials', 'true') self.set_header('Access-Control-Allow-Origin', self.request.headers.get('Origin')) if self._status_code in ( 204, 304) or 100 <= self._status_code < 200: # 这些状态下response中不能有body,所以不应该write return # 判断响应是否是chunk传输 transfer_encoding_header = response.headers.get( "Transfer-Encoding") if transfer_encoding_header is None or transfer_encoding_header != "chunked": # 不是的话按照正常逻辑处理 self.write(response.content) else: # chunk传输,chunk处理 self._headers.pop("Transfer-Encoding") # 注意一定要pop掉 raw_content = response.raw chunk_size = 1024 while True: # 分块读取响应, 并flush到客户端 chunk = raw_content.read(chunk_size) self.write(chunk) await self.flush() if len(chunk) < chunk_size: break else: self.set_status(500) self.write(result['value']) async def post(self, *args, **kwargs): output = {'result': {}, 'finish': False} thread = threading.Thread(target=gateway_service, args=(self.request, output)) thread.setDaemon(True) thread.start() while not output['finish']: await asyncio.sleep(0.01) result = output['result'] if result['status'] == 'ok': new_access_token = result['value'].get( 'new_access_token') # 用 get 而不是 [] 来取值,因为可能不存在 new_refresh_token = result['value'].get('new_refresh_token') response = result['value']['response'] if new_access_token is not None and new_refresh_token is not None: self.set_cookie('access_token', new_access_token) self.set_cookie('refresh_token', new_refresh_token) self.set_status(response.status_code) self._headers = HTTPHeaders(response.headers) # 注意:需要强制类型转换 if self.request.headers.get('Origin'): self.set_header('Access-Control-Allow-Credentials', 'true') self.set_header('Access-Control-Allow-Origin', self.request.headers.get('Origin')) if self._status_code in (204, 304) or 100 <= self._status_code < 200: # 这些状态下response中不能有body,所以不应该write return self.write(response.content) else: self.set_status(500) self.write(result['value']) async def options(self, *args, **kwargs): # 允许跨域 self.set_status(204) self.set_header('Access-Control-Allow-Credentials', 'true') self.set_header('Access-Control-Allow-Origin', self.request.headers.get('Origin')) self.set_header("Access-Control-Allow-Headers", "content-type") self.set_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')