Python-Twisted:反向代理到HTTPS API:无法连接

时间:2016-02-27 00:11:17

标签: python twisted reverse-proxy lxc twisted.web

我正在尝试构建一个反向代理来与某些API(如Twitter,Github,Instagram)交谈,然后我可以使用我的反向代理调用我想要的任何(客户端)应用程序(将其视为API -manager)。

另外,我正在使用LXC容器来执行此操作。

例如,以下是我从Twisted Docs上的示例中入侵的最简单的代码:

from twisted.internet import reactor
from twisted.web import proxy, server
from twisted.python.log import startLogging
from sys import stdout
startLogging(stdout)

site = server.Site(proxy.ReverseProxyResource('https://api.github.com/users/defunkt', 443, b''))
reactor.listenTCP(8080, site)
reactor.run()

当我在容器中执行CURL时,我得到一个有效的请求(意味着我得到了适当的JSON响应)。

以下是我使用CURL命令的方法:

curl https://api.github.com/users/defunkt

这是我得到的输出:

{
  "login": "defunkt",
  "id": 2,
  "avatar_url": "https://avatars.githubusercontent.com/u/2?v=3",
  "gravatar_id": "",
  "url": "https://api.github.com/users/defunkt",
  "html_url": "https://github.com/defunkt",
  "followers_url": "https://api.github.com/users/defunkt/followers",
  "following_url": "https://api.github.com/users/defunkt/following{/other_user}",
  "gists_url": "https://api.github.com/users/defunkt/gists{/gist_id}",
  "starred_url": "https://api.github.com/users/defunkt/starred{/owner}{/repo}",
  "subscriptions_url": "https://api.github.com/users/defunkt/subscriptions",
  "organizations_url": "https://api.github.com/users/defunkt/orgs",
  "repos_url": "https://api.github.com/users/defunkt/repos",
  "events_url": "https://api.github.com/users/defunkt/events{/privacy}",
  "received_events_url": "https://api.github.com/users/defunkt/received_events",
  "type": "User",
  "site_admin": true,
  "name": "Chris Wanstrath",
  "company": "GitHub",
  "blog": "http://chriswanstrath.com/",
  "location": "San Francisco",
  "email": "chris@github.com",
  "hireable": true,
  "bio": null,
  "public_repos": 107,
  "public_gists": 280,
  "followers": 15153,
  "following": 208,
  "created_at": "2007-10-20T05:24:19Z",
  "updated_at": "2016-02-26T22:34:27Z"
}

但是,当我尝试使用以下方法通过Firefox获取代理时:

  

http://10.5.5.225:8080/

我得到:“无法连接”

这就是我的Twisted日志:

  

2016-02-27 [ - ]登录日志。

     

2016-02-27 [ - ]网站从8080开始

     

2016-02-27 [ - ]开始工厂

     

2016-02-27 [ - ]开始工厂

     

2016-02-27 [ - ]“10.5.5.225” - - [27 / Feb / 2016:+0000]“GET / HTTP / 1.1”501 26“ - ”“Mozilla / 5.0(X11; Debian; Linux x86_64; rv:44.0)Gecko / 20100101 Firefox / 44.0“

     

2016-02-27 [ - ]停止工厂

如何使用Twisted进行API调用(现在大多数API都是HTTPS)并获得所需的响应(基本上,“200”响应/ JSON应该是什么)?

我试着看这个问题:Convert HTTP Proxy to HTTPS Proxy in Twisted

但从编码的角度来看,它没有多大意义(或提及反向代理的任何内容)。

**编辑:我还尝试使用以下方法切换HTTPS API调用以进行常规HTTP调用:

  

curl http [colon] [slash] [slash] openlibrary [dot] org [slash] authors [slash] OL1A.json

(上面的网址已经过格式化以避免链接冲突问题)

但是,我的浏览器仍然会出现同样的错误(如上所述)。

** Edit2:我试过运行你的代码,但是我收到了这个错误:

Error-screenshot

如果查看图像,您将看到错误(运行代码时):

  

builtins.AttributeError:'str'对象没有属性'decode'

1 个答案:

答案 0 :(得分:4)

如果您阅读API documentation for ReverseProxyResource,您会看到__init__的签名是:

def __init__(self, host, port, path, reactor=reactor):

和" host"被记录为"要代理的Web服务器的主机"。

因此,您传递的是Twisted期望主机的URI。

更糟糕的是,ReverseProxyResource专为在网络服务器上本地使用而设计,并且不会完全支持https://开箱即用的网址。

确实有一个(非常有限的)可扩展性钩子 - proxyClientFactoryClass - 并为ReverseProxyResource道歉而没有开箱即用的东西,我将展示您如何使用它来扩展ReverseProxyResource以添加https://支持,以便您可以使用GitHub API :)。

from twisted.web import proxy, server
from twisted.logger import globalLogBeginner, textFileLogObserver
from twisted.protocols.tls import TLSMemoryBIOFactory
from twisted.internet import ssl, defer, task, endpoints
from sys import stdout
globalLogBeginner.beginLoggingTo([textFileLogObserver(stdout)])

class HTTPSReverseProxyResource(proxy.ReverseProxyResource, object):
    def proxyClientFactoryClass(self, *args, **kwargs):
        """
        Make all connections using HTTPS.
        """
        return TLSMemoryBIOFactory(
            ssl.optionsForClientTLS(self.host.decode("ascii")), True,
            super(HTTPSReverseProxyResource, self)
            .proxyClientFactoryClass(*args, **kwargs))
    def getChild(self, path, request):
        """
        Ensure that implementation of C{proxyClientFactoryClass} is honored
        down the resource chain.
        """
        child = super(HTTPSReverseProxyResource, self).getChild(path, request)
        return HTTPSReverseProxyResource(child.host, child.port, child.path,
                                         child.reactor)

@task.react
def main(reactor):
    import sys
    forever = defer.Deferred()
    myProxy = HTTPSReverseProxyResource('api.github.com', 443,
                                        b'/users/defunkt')
    myProxy.putChild("", myProxy)
    site = server.Site(myProxy)
    endpoint = endpoints.serverFromString(
        reactor,
        dict(enumerate(sys.argv)).get(1, "tcp:8080:interface=127.0.0.1")
    )
    endpoint.listen(site)
    return forever

如果您运行此操作,curl http://localhost:8080/应该按预期执行。

我已经冒昧地将Twisted代码现代化了; endpoints代替listenTCPlogger代替twisted.python.logreact,而不是自己启动反应堆。

最后一个奇怪的小putChild部分是因为当我们传递b"/users/defunkt"作为路径时,这意味着/的请求将导致客户请求/users/defunkt/ (注意斜杠),这是GitHub API中的404。如果我们明确地将空子段路径代理,就好像它没有尾随段,我相信它会做你期望的。

请注意 :从纯文本HTTP到加密HTTPS的代理可能 非常危险 ,所以我和#39; ve在这里添加了localhost-only的默认监听界面。如果您的字节在实际网络上传输,则应确保使用TLS正确加密它们。