在用 Tornado 建站,打算将 UI 渲染和后端操作独立为两个进程,用 API 互相操作数据。
我的做法是前后端可以同时被外部访问,类似于这样的 nginx 配置:
location / {
proxy_pass http://test_tornado;
include proxy_params;
}
location ~ ^/api {
proxy_pass http://test_tornado_backend;
include proxy_params;
}
在本地测试的时候是没有 nginx 的,是让 Tornado 直接跑。
于是在前端的代码中绑定 /api 到下面这个 Handler:
import tornado
import tornado.gen
import tornado.options
import tornado.httpclient
import tornado.web
class APIProxyHandler(tornado.web.RequestHandler):
@tornado.gen.coroutine
def get(self):
yield self.post()
@tornado.gen.coroutine
def post(self):
http_client = tornado.httpclient.AsyncHTTPClient()
request_headers = self.request.headers.copy()
request_headers.add('X-Forwarded-For', self.request.remote_ip)
request_options = {
'url': '?'.join([tornado.options.options.backend]+self.request.uri.split('?', 1)[1:]),
'method': self.request.method,
'headers': request_headers,
'body': self.request.body,
'user_agent': self.request.headers.get('User-Agent', 'Tornado/%s' % tornado.version),
'connect_timeout': 60,
'request_timeout': 60,
'follow_redirects': False,
'use_gzip': True,
'allow_nonstandard_methods': True,
'allow_ipv6': True,
}
try:
response = yield http_client.fetch(tornado.httpclient.HTTPRequest(**request_options))
except tornado.httpclient.HTTPError as e:
response = e.response
self.set_status(response.code, response.reason)
existed_headers = set()
for header_name, header_value in response.headers.get_all():
if header_name.lower() in ('content-encoding', 'content-length'):
continue
elif header_name in existed_headers:
self.add_header(header_name, header_value)
else:
self.set_header(header_name, header_value)
existed_headers.add(header_name)
self.finish(response.body or None)
没有评论:
发表评论