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

Posted

技术标签:

【中文标题】Python-Twisted:反向代理到 HTTPS API:无法连接【英文标题】:Python-Twisted: Reverse Proxy to HTTPS API: Could not connect 【发布时间】:2016-06-10 09:27:24 【问题描述】:

我正在尝试构建一个反向代理来与某些 API(如 Twitter、Github、Instagram)对话,然后我可以使用我的反向代理调用我想要的任何(客户端)应用程序(把它想象成一个 API -经理)。

另外,我正在使用 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[冒号][slash][slash]openlibrary[dot]org[slash]authors[slash]OL1A.json

(上面的 URL 已被格式化以避免链接冲突问题)

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

**Edit2:我尝试过运行您的代码,但出现此错误:

Error-screenshot

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

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

【问题讨论】:

当我运行这个例子时,curl 和 Firefox 都说“无法连接”,所以我不确定你在做什么来获得正确的 JSON 响应。您是否完全按照编写的方式运行代码示例? 哇,您是 Twisted 的创始人,很高兴认识您,先生!我正在运行代码:python3 file.py。就输出而言,我正在编辑我的问题以说明我如何使用 curl 和我得到的输出。可能是您受到 github API 的速率限制(没有 API 密钥的公共调用有一些限制),但我成功地获得了 JSON 响应。 也很高兴认识您。感谢您使用 Twisted :)。既然你已经明确了你是如何运行你的命令的,我可以回答它...... 【参考方案1】:

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

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

并且“host”被记录为“要代理的 Web 服务器的主机”。

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

更糟糕的是,ReverseProxyResource 专为在 Web 服务器上本地使用而设计,并且不相当支持开箱即用的 https:// URL。

确实有一个(非常有限的)可扩展性钩子 - 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 CproxyClientFactoryClass 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 代替 listenTCP,logger 代替 twisted.python.logreact 而不是自己启动反应器。

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

请注意:从纯文本 HTTP 代理到加密 HTTPS 可能非常危险,所以我'已在此处添加了仅限 localhost 的默认侦听接口。如果您的字节通过实际网络传输,则应确保它们已使用 TLS 正确加密。

【讨论】:

感谢先生的详细解答。我首先想说的是,没有必要为软件无法开箱即用而道歉,我的明确用例没有得到解决并不是任何人的错 :) 我能够成功运行代码,但我收到一个错误,我将在上面的输入中粘贴为编辑/图像。我试图解决它,因为我认为这是 python3 的字节/字符串问题,但到目前为止还没有运气。 由于我的分数低,我无法为您的答案投票,但我将其标记为已选答案。

以上是关于Python-Twisted:反向代理到 HTTPS API:无法连接的主要内容,如果未能解决你的问题,请参考以下文章

Nginx反向代理+负载均衡

Nginx反向代理:将所有http请求重定向到https

在网站前面使用反向代理将 http 请求从 iframe 中重定向到网站

正反向代理

Nginx 最全操作——nginx反向代理(5)

使用 Docker 并希望 HTTP 到 HTTPS 使用 NGINX 反向代理到 HTTP Grafana