2013-02-04 10 views
6

में HTTP POST अनुरोधों के साथ असंगत व्यवहार एक पायथन (डब्लूएसजीआई) और एक नोडजेएस + एक्सप्रेस एप्लिकेशन के बीच एक POST अनुरोध करने का प्रयास कर रहा है। वे विभिन्न सर्वरों पर हैं।पाइथन

समस्या यह है कि जब विभिन्न IP पते (अर्थात प्राइवेट नेटवर्क बनाम सार्वजनिक नेटवर्क) का उपयोग कर, सार्वजनिक नेटवर्क पर एक urllib2 अनुरोध सफल होता है, लेकिन निजी नेटवर्क के लिए एक ही अनुरोध एक 502 Bad Gateway या URLError [32] Broken pipe साथ विफल रहता है।

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

print r.text 

और एक 200 OK प्रतिक्रिया मिल:

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

res = urllib2.urlopen(req) 

print f.read() 

अब, मैं भी इस तरह के अनुरोध कोड किया है, requests का उपयोग कर:

urllib2 कोड मैं उपयोग कर रहा हूँ यह है। यह वैकल्पिक विधि दोनों नेटवर्क के लिए काम करता है।

मुझे यह जानने में दिलचस्पी है कि urllib2 अनुरोध के लिए कुछ अतिरिक्त कॉन्फ़िगरेशन की आवश्यकता है, जो मुझे नहीं पता, या अगर मुझे कुछ नेटवर्क कॉन्फ़िगरेशन देखने की आवश्यकता है जो शायद गायब हो (मुझे विश्वास नहीं है मामला है, वैकल्पिक अनुरोध विधि काम करता है, लेकिन मैं निश्चित रूप से गलत हो सकता है)।

इसके साथ किसी भी सुझाव या पॉइंटर्स की सराहना की जाएगी। धन्यवाद!

+1

यदि आप दोनों द्वारा भेजे गए शीर्षकों की तुलना करते हैं, तो वे समान नहीं होंगे। (उदाहरण के लिए, 'अनुरोध 'को' स्वीकृति-एन्कोडिंग: gzip, deflate, compress' 'पर' डिफ़ॉल्ट 'को' एसीप्ट-एन्कोडिंग: पहचान' 'के दौरान डिफ़ॉल्ट रूप से डिफ़ॉल्ट रूप से परिभाषित किया जाता है।) प्रत्येक संस्करण के साथ अनुरोध शीर्षलेखों को कैप्चर करें, और सर्वर का उपयोग करके उन्हें फिर से चलाएं , उदाहरण के लिए, 'एनसी' और देखें कि यह कैसे प्रतिक्रिया करता है।या तो 'urllib2' हेडर के बारे में कुछ 502 त्रुटि उत्पन्न कर रहा है, या यह किसी प्रकार का रीडायरेक्ट/आदि कर रहा है। urllib2 द्वारा समझने वाले अनुरोध नहीं करते हैं। – abarnert

+0

इसके अलावा ... अगर यह 'अनुरोध' के साथ काम करता है, तो क्या कोई कारण है कि आप केवल 'अनुरोध' का उपयोग नहीं कर सकते हैं? – abarnert

+2

['urllib2.Request'] के लिए दस्तावेज़ (http://docs.python.org/2/library/urllib2.html#urllib2.Request) इंगित करता है कि * डेटा * पैरामीटर को urlencoded * अनुप्रयोग/x- www फार्म-urlencoded *। –

उत्तर

3

समस्या है कि यहाँ, के रूप में ऑस्टिन फिलिप्स, urllib2.Request के निर्माता के data पैरामीटर ने बताया है:

एक स्ट्रिंग अतिरिक्त डेटा को निर्दिष्ट सर्वर से भेजने के लिए हो सकता है ... data मानक में एक बफर होना चाहिए एप्लिकेशन/एक्स-www-form-urlencoded प्रारूप। Urllib.urlencode() फ़ंक्शन 2-टुपल्स का मैपिंग या अनुक्रम लेता है और इस प्रारूप में एक स्ट्रिंग देता है।

इसे urlencoded डेटा के बजाय JSON-encoded डेटा पास करके, आप इसे कहीं भ्रमित कर रहे हैं।

आंकड़ों के अनुरोध डेटा सेट करें:

हालांकि, Request एक विधि add_data है। इसे HTTP हैंडलर को छोड़कर सभी हैंडलर द्वारा अनदेखा किया जाता है - और वहां यह एक बाइट स्ट्रिंग होना चाहिए, और जीईटी के बजाय अनुरोध पोस्ट को बदल देगा।

आप इस का उपयोग करते हैं, तो आप शायद भी 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) 

एक टिप्पणी में, आप ने कहा:

कारण बाहर क्यों खोजने के बिना मैं सिर्फ अनुरोध पर स्विच नहीं करना चाहते मैं यह समस्या देख रहा हूं कि कुछ गहरा अंतर्निहित मुद्दा हो सकता है कि यह इंगित करता है कि बाद में वापस आ सकता है और बाद में समस्याओं का पता लगाना मुश्किल हो सकता है।

यदि आप गहरे अंतर्निहित मुद्दों को ढूंढना चाहते हैं, तो आप केवल अपने क्लाइंट-साइड स्रोत को देखकर ऐसा नहीं करेंगे। "एक्स काम क्यों करता है लेकिन वाई विफल रहता है" को समझने का पहला कदम? नेटवर्क कोड के साथ यह पता लगाने के लिए कि बाइट एक्स और वाई प्रत्येक भेजता है। फिर आप प्रासंगिक अंतर को कम करने की कोशिश कर सकते हैं, और उसके बाद पता लगाएं कि आपके कोड का कौन सा हिस्सा वाई को प्रासंगिक स्थान पर गलत डेटा भेजने के कारण है।

आप सेवा पर चीजों को लॉग इन करके (यदि आप इसे नियंत्रित करते हैं), Wireshark चलाना आदि कर सकते हैं, लेकिन सरल मामलों के लिए सबसे आसान तरीका नेटकैट है। आपको अपने सिस्टम के लिए man nc पढ़ने की आवश्यकता होगी (और, विंडोज़ पर, आपको इसे चलाने से पहले नेटकैट प्राप्त करने और इंस्टॉल करने की आवश्यकता होगी), क्योंकि प्रत्येक संस्करण के लिए वाक्यविन्यास अलग है, लेकिन यह हमेशा nc -kl 12345 जैसा कुछ आसान है।

फिर, अपने ग्राहक में, होस्ट नाम के स्थान पर localhost:12345 का उपयोग करने के लिए यूआरएल बदलें, और यह नेटकैट से जुड़ जाएगा और इसके 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) 

तो, यह क्यों काम कर रहा है? खैर, जावास्क्रिप्ट में, एकल-उद्धृत तार कानूनी हैं, साथ ही बैकस्लैश जैसी अन्य चीजें जेएसओएन में मान्य नहीं हैं, और किसी भी जेएस कोड जो पार्सिंग के लिए प्रतिबंधित-eval (या, बदतर, कच्चे eval) का उपयोग करता है उसे स्वीकार करेगा । और, क्योंकि इस वजह से बहुत से लोगों को खराब JSON लिखने के लिए उपयोग किया जाता है, इसलिए कई ब्राउज़रों के मूल JSON पार्सर्स और अन्य भाषाओं में कई JSON पुस्तकालयों में सामान्य त्रुटियों की अनुमति देने के लिए कामकाज होते हैं। लेकिन आपको उस पर भरोसा नहीं करना चाहिए।

+0

उत्कृष्ट जवाब। 'नेटकैट' टिप बहुत उपयोगी है, और मैं भविष्य के उपयोग के लिए इसे ध्यान में रखूंगा। मैं अपने वास्तविक कोड के लिए 'json.dumps' का उपयोग करता हूं, लेकिन मैंने प्रश्न आकार को कम करने के लिए इसे छोड़ दिया। हालांकि, यह एक बहुत अच्छा अवलोकन है और मैं भविष्य के उपयोग के लिए इसे ध्यान में रखूंगा। बहुत बहुत धन्यवाद। –