3

APIを提供するサーバーがあります。

私はしばらくそれを使用していますが、最近私は、私たちのAPIサーバーからいくつかの宛先への一種のサーバー偏見(一部の送信者には親切で、他の送信者には悪い)と呼んでいるものを経験しています。何が起こっているかを正確に知っています。

一部の要求は TCP リセット(RST) で応答されますが、他の要求は適切に応答されます(200 ステータス、期待されるコンテンツ)。

これがサーバーで明示的に行われていないこと (実際には拒否する宛先を選択しているわけではないこと) と、試したクライアントごとに常に同じ結果が得られること (つまり、動作は決定論的であり、送信者のみに依存します-少なくとも明らかに)。

これは私が送信している実際のリクエストです:

GET /api/guilherme@buddycloud.org/metadata/posts HTTP/1.1
Host: demo.buddycloud.org

これは私が書いた python コードで、さまざまな場所で実行しています。

from requests import Request, Session

headers = {
    'Accept' : '*/*',
    'Accept-Encoding' : 'gzip,deflate,sdch',
    'Accept-Language' : 'en-US,en;q=0.8,pt-BR;q=0.6,pt;q=0.4',
    'Cache-Control' : 'no-cache',
    'Host' : 'demo.buddycloud.org'
}

req = Request('GET',
'https://demo.buddycloud.org/api/guilherme@buddycloud.org/metadata/posts',
headers=headers)

r = req.prepare()
print r.url

s = Session()
resp = s.send(r, verify=False)

print resp, resp.ok
print resp.content

私が試したいくつかの異なるシナリオ:

Windows 7 64 ビット、Python 2.7.3、リクエスト 1.2.3

このコードを実行すると、次の例外が発生しました。

requests.exceptions.ConnectionError:
HTTPSConnectionPool(host='demo.buddycloud.org', port=443):
Max retries exceeded with url: /api/guilherme@buddycloud.org/metadata/posts
(Caused by <class 'socket.error'>:
[Errno 10054] An existing connection was forcibly closed by the remote host)

Wireshark を使用して、サーバーから TCP リセットを取得したため、これが発生していることに気付きました。 Wireshark の出力イメージ

Ubuntu、Python 2.7.3、リクエスト 1.2.3

まったく同じコードを実行しましたが、問題はありませんでしたが、予想される応答は次のとおりです。

https://demo.buddycloud.org/api/guilherme@buddycloud.org/metadata/posts
<Response [200]> True
{
  "title" : "guilherme@buddycloud.org Channel Posts",
  "description":"This is my buddycloud channel =)",
  "access_model":"open",
  "creation_date":"2013-04-13T15:24:53.471Z",
  "channel_type":"personal",
  "default_affiliation":"publisher"
}

この時点で、Windows x Linux の問題であると推測できますが、シナリオの 1 つは Linux 環境であることがわかりますが、それでも同じ問題が発生します。

郵便屋さんを通して

予想どおり、うまく機能します。郵便屋さんのプリントスクリーン

Heroku サーバーでは、Python 2.7.4、Requests 1.2.3

API に対して同じ呼び出しを発行するアプリがあります。かなり似たようなエラーがそこで発生し、理由は同じだと確信しています (サーバーが TCP リセットを送信している)。これは発生する例外です:

HTTPSConnectionPool(host='demo.buddycloud.org', port=443):
Max retries exceeded with url:
/api/guilherme@buddycloud.org/metadata/posts
(Caused by : [Errno 104] Connection reset by peer)

ですから、サーバーがこのように動作する理由を知りたくてたまりません。問題は自分の側にあると考えるのに多くの時間を費やしましたが、そうではなく、サーバーの何か、おそらく設定ミスまたは SSL 関連の何かが原因であると推測しています。

私のコードがpython-requestsを介して送信するヘッダーは、Postman が送信するヘッダーと同じであることに注意してください。実際には、Postman の成功した要求をモックしようとしていますが、うまくいきません。

また、これを実行しようとしたすべての場所で、まったく同じバージョンの Python と Requests があることに注意してください。

誰かが何が起こっているのかを知るのを手伝ってくれますか? よろしくお願いいたします。ご不明な点がございましたら、お気軽にお問い合わせください。

4

2 に答える 2

3

SSLネゴシエーションに問題があるようです。このコードはherokuで機能します。使用'SSLv3'も機能します。'SSLv23'(デフォルト) 壊れます。理由は聞かないでください。

from requests import Session
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager


class SSLAdapter(HTTPAdapter):
    '''An HTTPS Transport Adapter that uses an arbitrary SSL version.'''
    def __init__(self, ssl_version=None, **kwargs):
        self.ssl_version = ssl_version

        super(SSLAdapter, self).__init__(**kwargs)

    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(num_pools=connections,
                                       maxsize=maxsize,
                                       block=block,
                                       ssl_version=self.ssl_version)

s = Session()
s.mount('https://', SSLAdapter('TLSv1'))
req = s.get('https://demo.buddycloud.org/api/guilherme@buddycloud.org/metadata/posts',    verify=False)
print(req)

( SSLAdapter@Lukasa さんのブログより)

于 2013-07-05T16:58:17.973 に答える
0

問題は Request ヘッダーにあるようです。

次のヘッダーをリクエストに追加します -

Connection: keep-alive
Cache-Control: no-cache
Pragma: no-cache

リクエストから次のヘッダーを削除します -

Accept-Encoding: gzip, deflate

もう一度テストすると、うまくいくはずです。

于 2013-07-05T05:32:22.037 に答える