2016-02-27 8 views
1

Я пытаюсь создать обратный прокси-сервер, чтобы поговорить с определенными API-интерфейсами (например, Twitter, Github, Instagram), после чего я могу позвонить с моим обратным прокси-сервером на любой (клиентских) приложений, которые я хочу (подумайте об этом как API-менеджер).Python-Twisted: обратный прокси-сервер для HTTPS-API: не удалось подключиться

Кроме того, я использую LXC-контейнер для этого.

Например, вот простейший код, который я взломал из примеров на витых 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": "[email protected]", 
    "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 [-] Log opened.

2016-02-27 [-] Site starting on 8080

2016-02-27 [-] Starting factory

2016-02-27 [-] Starting factory

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 [-] Stopping factory

Как я могу использовать Twisted сделать вызов API (большинство API-интерфейсы являются HTTPS в настоящее время в любом случае) и получить необходимый ответ (в основном, то, что «200» ответа/JSON должен быть)?

Я попытался, глядя на этот вопрос: Convert HTTP Proxy to HTTPS Proxy in Twisted

Но это не имеет особого смысла от кодирования точки зрения из-(или говоря ничего об обратном-проксирование).

** Edit: я также пытался переключение из вызова HTTPS API для обычного вызова HTTP с помощью:

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

(URL выше, был отформатирован, чтобы избежать проблем канального конфликта)

Однако, Я по-прежнему получаю ту же ошибку в своем браузере (как упоминалось выше).

** Edit2: Я попытался запустить свой код, но я получаю эту ошибку:

Error-screenshot

Если вы посмотрите на изображение, вы увидите сообщение об ошибке (при выполнении кода):

builtins.AttributeError: 'str' object has no attribute 'decode'

+0

Когда я запускаю этот пример, 'curl' и Firefox говорят, что« не удалось подключиться », поэтому я не уверен, что вы делаете, чтобы получить правильный ответ JSON. Вы используете образец кода точно так же, как написано? – Glyph

+0

Ничего себе, вы основатель Twisted, приятно познакомиться с вами, сэр! Я запускаю код с помощью: 'python3 file.py'. Что касается выхода, я редактирую свой вопрос, чтобы указать, как я использовал завиток и полученный результат. Возможно, что вы ограничены по скорости API-интерфейсом github (существует ограничение на публичные вызовы без ключа API), но мне удалось получить ответ JSON. – coolpy

+0

Удовольствие от встречи с вами. Спасибо за использование Twisted :). Теперь, когда вы ясно дали понять, как вы управляете своей командой, я могу ответить на него ... – Glyph

ответ

3

Если вы читали API documentation for ReverseProxyResource, вы увидите, что подпись __init__ является:

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

и «host» документируется как «хозяин веб-сервера для прокси».

Итак, вы передаете URI, где Twisted ожидает хост.

еще хуже, ReverseProxyResource предназначен для локального использования на веб-сервере, а не вполне поддержка 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 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/ должен делать то, что вы ожидаете.

Я взял на себя смелость модернизировать ваш витой код; endpoints вместо listenTCP, logger вместо twisted.python.log и react вместо запуска реактора самостоятельно.

Странные немного putChild куска в конце есть, потому что, когда мы проходим b"https://stackoverflow.com/users/defunkt" как путь, это означает, что запрос на / приведет к клиенту с просьбой /users/defunkt/ (обратите внимание на слэш), который является 404 в API GitHub в , Если мы явно проксируем путь с пустым дочерним сегментом, как если бы у него не было конечного сегмента, я считаю, что он будет делать то, что вы ожидаете.

ОБРАТИТЕ ВНИМАНИЕ: проксирование из простого текстового HTTP к зашифрованным HTTPS может быть крайне опасно, поэтому я добавил по умолчанию интерфейс прослушивания здесь локальный только. Если ваши байты проходят через реальную сеть, вы должны убедиться, что они правильно зашифрованы с помощью TLS.

+0

Благодарим вас за подробный ответ. Прежде всего я хотел бы сказать, что нет необходимости приносить извинения за то, что программное обеспечение не может работать из коробки, это не ошибка каких-либо ящиков, что мой явный вариант использования не был адресован :) Я успешно могу запустить код, но я получаю сообщение об ошибке, которое я вставляю в качестве редактирования/изображения в свой ввод выше. Я попытался обратиться к нему, так как я думаю, что это проблема с байтом/строкой с python3, но пока не повезло. – coolpy

+0

Я не могу поддержать ваш ответ из-за моего низкого балла, но я отметил его как выбранный ответ. – coolpy

 Смежные вопросы

  • Нет связанных вопросов^_^