This article describes how to implement a simple online proxy tutorial in the Python Tornado framework. the proxy function is a common network programming implementation, the need of friends can refer to the implementation of proxy many ways, popular web servers are also mostly agent functions, such as http://www.tornadoweb.cn with nginx proxy functions do tornadoweb official website image.
Recently, I am developing a background program (Server) for mobile applications (hereinafter referred to as apps). This application needs to call the API of another Platform. For this system, an optional implementation method is that the APP interacts with the Server and Platform at the same time; the other is to encapsulate the Platform API on the Server, the APP only interacts with the Server. Obviously, the system architecture of the latter method will be clearer, and APP programming will be relatively simple. So how can we encapsulate the Platform API on the Server? the first thing I want to consider is to implement it in proxy mode. It happened that someone in the Tornado mail group was discussing using Tornado as a proxy recently. the application scenario mentioned by the Post-Master is very similar to the scenario I encountered, I have sorted out and simplified the original post code. the source code is as follows:
# -*- coding: utf-8 -*-## Copyright(c) 2011 Felinx Lee & http://feilong.me/## Licensed under the Apache License, Version 2.0 (the "License"); you may# not use this file except in compliance with the License. You may obtain# a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the# License for the specific language governing permissions and limitations# under the License. import logging import tornado.httpserverimport tornado.ioloopimport tornado.optionsimport tornado.webimport tornado.httpclientfrom tornado.web import HTTPError, asynchronousfrom tornado.httpclient import HTTPRequestfrom tornado.options import define, optionstry: from tornado.curl_httpclient import CurlAsyncHTTPClient as AsyncHTTPClientexcept ImportError: from tornado.simple_httpclient import SimpleAsyncHTTPClient as AsyncHTTPClient define("port", default=8888, help="run on the given port", type=int)define("api_protocol", default="http")define("api_host", default="feilong.me")define("api_port", default="80")define("debug", default=True, type=bool) class ProxyHandler(tornado.web.RequestHandler): @asynchronous def get(self): # enable API GET request when debugging if options.debug: return self.post() else: raise HTTPError(405) @asynchronous def post(self): protocol = options.api_protocol host = options.api_host port = options.api_port # port suffix port = "" if port == "80" else ":%s" % port uri = self.request.uri url = "%s://%s%s%s" % (protocol, host, port, uri) # update host to destination host headers = dict(self.request.headers) headers["Host"] = host try: AsyncHTTPClient().fetch( HTTPRequest(url=url, method="POST", body=self.request.body, headers=headers, follow_redirects=False), self._on_proxy) except tornado.httpclient.HTTPError, x: if hasattr(x, "response") and x.response: self._on_proxy(x.response) else: logging.error("Tornado signalled HTTPError %s", x) def _on_proxy(self, response): if response.error and not isinstance(response.error, tornado.httpclient.HTTPError): raise HTTPError(500) else: self.set_status(response.code) for header in ("Date", "Cache-Control", "Server", "Content-Type", "Location"): v = response.headers.get(header) if v: self.set_header(header, v) if response.body: self.write(response.body) self.finish() def main(): tornado.options.parse_command_line() application = tornado.web.Application([ (r"/.*", ProxyHandler), ]) http_server = tornado.httpserver.HTTPServer(application) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start() if __name__ == "__main__": main()
After running the above code, accessing http: // localhost: 8888/will display the homepage of the flying dragon blog, that is, the proxy accesses the content of http://feilong.me.
I want to use a program as a proxy instead of using Nginx as a proxy. one of them is that the program can easily control which APIs of Platform need proxy, which are to be blocked, and which may be overwritten (for example, the login of the Server may not directly proxy the login of Platform, but must call the login API of Platform ).
The above code is just a simple page content proxy, and does not further parse the page, such as link replacement, and so on. these will be developed by a friend of interest. Based on the above code, you can extend it to implement a complete online proxy program.
This code has been put into my experiment project. for details, see examples.
Reprinted please indicate the source: http://feilong.me/2011/09/tornado-as-a-proxy