在Python的Tornado框架中實(shí)現(xiàn)簡(jiǎn)單的在線代理的教程
實(shí)現(xiàn)代理的方式很多種,流行的web服務(wù)器也大都有代理的功能,比如http://www.tornadoweb.cn用的就是nginx的代理功能做的tornadoweb官網(wǎng)的鏡像。
最近,我在開(kāi)發(fā)一個(gè)移動(dòng)運(yùn)用(以下簡(jiǎn)稱APP)的后臺(tái)程序(Server),該運(yùn)用需要調(diào)用到另一平臺(tái)產(chǎn)品(Platform)的API。對(duì)于這個(gè)系統(tǒng)來(lái)說(shuō),可選的一種實(shí)現(xiàn)方式方式是APP同時(shí)跟Server&Platform兩者交互;另一種則在Server端封裝掉Platform的API,APP只和Server交互。顯然后一種方式的系統(tǒng)架構(gòu)會(huì)清晰些,APP編程時(shí)也就相對(duì)簡(jiǎn)單。那么如何在Server端封裝Platform的API呢,我首先考慮到的就是用代理的方式來(lái)實(shí)現(xiàn)。碰巧最近Tornado郵件群組里有人在討論using Tornado as a proxy,貼主提到的運(yùn)用場(chǎng)景跟我這碰到的場(chǎng)景非常的相似,我把原帖的代碼做了些整理和簡(jiǎn)化,源代碼如下:
# -*- 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.httpserver import tornado.ioloop import tornado.options import tornado.web import tornado.httpclient from tornado.web import HTTPError, asynchronous from tornado.httpclient import HTTPRequest from tornado.options import define, options try: from tornado.curl_httpclient import CurlAsyncHTTPClient as AsyncHTTPClient except 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()
運(yùn)行上面的代碼后,訪問(wèn) http://localhost:8888/ 將會(huì)完整顯示飛龍博客的首頁(yè),即代理訪問(wèn)了http://feilong.me/的內(nèi)容。
我考慮用程序的方式來(lái)做代理而不是直接用Nginx來(lái)做代理,其中一點(diǎn)是考慮到用程序可以很容易的控制Platform的哪些API是需要代理的,而哪些是要屏蔽掉的,還有哪些可能是要重寫(xiě)的(比如Server的login可能不能直接代理Platform的login,但卻要調(diào)用到Platform的login API)。
以上這段代碼只是做了簡(jiǎn)單的頁(yè)面內(nèi)容代理,并沒(méi)有對(duì)頁(yè)面進(jìn)行進(jìn)一步的解析處理,比如鏈接替換等,這些就交個(gè)有興趣的朋友去開(kāi)發(fā)了。基于以上這段代碼,將其擴(kuò)展一下,是完全可以實(shí)現(xiàn)一個(gè)完整的在線代理程序的。
這段代碼我已放到了我的實(shí)驗(yàn)項(xiàng)目里,見(jiàn)https://bitbucket.org/felinx/labs,我將會(huì)放更多類似于這樣的實(shí)驗(yàn)性質(zhì)的小項(xiàng)目到這個(gè)repository里來(lái),有興趣的朋友可以關(guān)注一下。
轉(zhuǎn)載請(qǐng)注明出處:http://feilong.me/2011/09/tornado-as-a-proxy
相關(guān)文章
python逐行讀寫(xiě)txt文件的實(shí)例講解
下面小編就為大家分享一篇python逐行讀寫(xiě)txt文件的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-04-04Python深度學(xué)習(xí)pytorch神經(jīng)網(wǎng)絡(luò)多輸入多輸出通道
這篇文章主要為大家介紹了Python深度學(xué)習(xí)中pytorch神經(jīng)網(wǎng)絡(luò)多輸入多輸出通道的詳解有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10python+pillow繪制矩陣蓋爾圓簡(jiǎn)單實(shí)例
這篇文章主要介紹了Python+pillow繪制矩陣蓋爾圓簡(jiǎn)單實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01TensorFlow車(chē)牌識(shí)別完整版代碼(含車(chē)牌數(shù)據(jù)集)
這篇文章主要介紹了TensorFlow車(chē)牌識(shí)別完整版代碼(含車(chē)牌數(shù)據(jù)集),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08使用Python實(shí)現(xiàn)企業(yè)微信通知功能案例分析
這篇文章主要介紹了使用Python實(shí)現(xiàn)企業(yè)微信通知功能,主要目的是通過(guò)企業(yè)微信應(yīng)用給企業(yè)成員發(fā)消息,通過(guò)案例分析給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04