2013-02-04 16 views
6

Python(WSGI)アプリケーションとNodeJS + Expressアプリケーションの間でPOST要求を試行しています。彼らは別のサーバー上にあります。PythonでのHTTP POST要求の不一致動作

問題は(対公衆ネットワーク、すなわちプライベートネットワーク)を異なるIPアドレスを使用している場合、パブリックネットワーク上のurllib2要求が成功したということですが、プライベートネットワークのための同じ要求が502 Bad GatewayまたはURLError [32] Broken pipeで失敗します。 requestsを使用して今、私はまた、このような要求をコード化している

req = urllib2.Request(url, "{'some':'data'}", {'Content-Type' : 'application/json; charset=utf-8'}) 

res = urllib2.urlopen(req) 

print f.read() 

、::

私が使用しているurllib2コードはこれです

r = requests.post(url, headers = {'Content-Type' : 'application/json; charset=utf-8'}, data = "{'some':'data'}") 

print r.text 

そして200 OK応答を取得します。この代替方法は、両方のネットワークで機能します。

私が知らないurllib2リクエストに必要な追加設定があるかどうかを知りたい場合、または欠落している可能性があるネットワーク設定を調べる必要がある場合は興味があります(私はこれを信じません代わりのリクエストメソッドが機能するので、そのケースですが、間違っている可能性があります)。

これに関するご意見やご指摘をいただければ幸いです。ありがとう!

+1

2者が送信したヘッダーを比較すると、両者は同じではありません。 (例えば、 'requests'はデフォルトで' Accept-Encoding:gzip、deflate、compress'を行い、 'urllib'を' Accept-Encoding:identity'にします。)リクエストヘッダを各バージョンで取得し、例えば、 'nc'とそれがどのように応答するか見ることができます。'urllib2'ヘッダに関する何かが502エラーを引き起こしているか、何らかのリダイレクト/ etcをしています。その要求はurllib2によって理解することはできません。 – abarnert

+0

また、 'requests'で動作する場合、単に' requests'を使うことができない理由がありますか? – abarnert

+2

['urllib2.Request'](http://docs.python.org/2/library/urllib2.html#urllib2.Request)のドキュメントによれば、* data *パラメータは* application/x- www-form-urlencoded * –

答えて

3

ここでの問題は、オースティン・フィリップスが指摘したように、urllib2.Requestのコンストラクタのdataパラメータ、ということである:

をサーバーに送信するために追加のデータを指定する文字列かもしれ... dataは標準でバッファする必要がありますアプリケーション/ x-www-form-urlencodedフォーマット。 urllib.urlencode()関数は2タプルのマッピングまたはシーケンスを取り、この形式の文字列を返します。

URLエンコードされたデータの代わりにJSONエンコードされたデータを渡すと、どこか混乱することになります。データへのリクエストデータを設定し

しかし、Requestは方法add_dataを持っています。これは、HTTPハンドラーを除くすべてのハンドラーで無視されます。その場合、バイトストリングでなければなりません。要求はGETではなくPOSTに変更されます。あなたがこれを使用する場合それは特にどこでもドキュメントに記載されていないようですが、

、あなたはおそらくも、コンストラクタでそれを渡すのではなく、add_headerを使用する必要があります。

ので、これは動作するはずです:コメントで

req = urllib2.Request(url) 
req.add_data("{'some':'data'}") 
req.add_header('Content-Type', 'application/json; charset=utf-8') 
res = urllib2.urlopen(req) 

を、あなたは言った:私はちょうど理由を発見することなく、要求に切り替えたくない

理由を私はこの問題が、これが後に戻って後で検出しにくい問題を引き起こす可能性がある深い根底にある問題があるかもしれないことを知っています。

深い根底にある問題を見つけたい場合は、クライアント側のソースを調べるだけでは解決できません。 「なぜXは動作するのですが、Yは失敗しますか」を理解するための第一歩です。ネットワークコードでは、XとYがそれぞれどのバイトを送信するかを正確に把握する必要があります。次に、適切な相違点を絞り込んで、コードのどの部分がYが適切な場所に間違ったデータを送る原因になっているかを調べることができます。

これは、サービス(コントロールしている場合)、実行中のWiresharkなどにログを記録することで可能ですが、最も簡単な方法はnetcatです。あなたのシステムにはman ncを読む必要があります(そして、Windowsでは、実行する前にnetcatを入手してインストールする必要があります)。なぜなら構文はバージョンごとに異なるからですが、常にnc -kl 12345のような単純なものです。

クライアントでは、ホスト名の代わりにlocalhost:12345を使用するようにURLを変更すると、netcatに接続してそのHTTPリクエストを送信し、端末にダンプされます。それをコピーしてnc HOST 80を使用して貼り付けて、実際のサーバーがどのように応答するかを確認し、それを使って問題がどこにあるかを絞り込むことができます。または、あなたが立ち往生した場合は、少なくともコピーしてあなたのSOの質問にデータを貼り付けることができます。


最後に一つは:(あなたがrequestsとまったく同じデータを送っているし、それが働いているので)これはほぼ確実にあなたの問題には関係ありませんが、それは、単一の使用しているので、あなたのデータは、実際に有効なJSONではありません二重引用符の代わりに引用符。 the docsによると、stringは次のように定義されています。一般的には

string 
    "" 
    " chars " 

(。ドキュメントは、同様の素敵なグラフィカルな表現を持っている)

、本当に簡単なテストケースを除き、あなたはJSONを書きたくはありません手で。多くの場合(あなたも含めて)、"…"json.dumps(…)に置き換えるだけで済みます。これは深刻な問題ではありません。だから:

req = urllib2.Request(url) 
req.add_data(json.dumps({'some':'data'})) 
req.add_header('Content-Type', 'application/json; charset=utf-8') 
res = urllib2.urlopen(req) 

だから、どうしてですか?まあ、JavaScriptでは、一重引用符で囲まれた文字列は合法的ですが、JSONでは有効でないバックスラッシュエスケープや、解析に制限付き評価(または悪い評価)を使用するJSコードなども認められます。また、多くの人が悪いJSONを書くことに慣れているので、多くのブラウザのネイティブなJSONパーサと他の言語のJSONライブラリの多くは、一般的なエラーを回避するための回避策があります。しかし、あなたはそれに頼るべきではありません。

+0

優れた答え。 'netcat'のヒントは非常に便利で、将来の使用のために覚えておきます。私は実際のコードで 'json.dumps'を使いますが、質問サイズを減らすためにそれを残しました。それは、しかし、非常に良い観察であり、私は将来の使用のためにそれを念頭に置くでしょう。どうもありがとう。 –

関連する問題