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
Example #2
0
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')