2012-11-11 14 views
5

Próbuję zastąpić curl za pomocą biblioteki zapytań Python &. Dzięki zwijaniu mogę przesłać pojedynczy plik XML do serwera REST za pomocą opcji curl -T. Nie mogłem zrobić tego samego z biblioteką żądań.Prześlij duży plik XML z biblioteką zapytań Pythona

Podstawowy scenariusz działa:

payload = '<person test="10"><first>Carl</first><last>Sagan</last></person>' 
headers = {'content-type': 'application/xml'} 
r = requests.put(url, data=payload, headers=headers, auth=HTTPDigestAuth("*", "*")) 

Kiedy zmienić ładowność do większego łańcucha otwierając plik XML, zawiesza metoda .put (używam biblioteki kodeków, aby uzyskać właściwe ciąg Unicode). Na przykład, plik 66 kb:

xmlfile = codecs.open('trb-1996-219.xml', 'r', 'utf-8') 
headers = {'content-type': 'application/xml'} 
content = xmlfile.read() 
r = requests.put(url, data=content, headers=headers, auth=HTTPDigestAuth("*", "*")) 

Szukałem w użyciu opcji wieloczęściowy (pliki), ale serwer nie wydaje się podoba.

Tak więc zastanawiałem się, czy istnieje sposób symulacji zachowania curl-T w bibliotece zapytań Pythona.

UPDATE 1: Program zawiesza się w tekstmate, ale zgłasza błąd UnicodeEncodeError w linii poleceń. Wydaje się, że to musi być problem. Pytanie brzmi: czy istnieje sposób wysyłania ciągów unicode do serwera z biblioteką żądań?

UPDATE 2: Dzięki komentarzowi Martijna Pietersa UnicodeEncodeError odszedł, ale pojawił się nowy problem. Z literalnej (ASCII) ciąg znaków XML, rejestrowanie wykazuje następujące linie:

2012-11-11 15:55:05,154 INFO Starting new HTTP connection (1): my.ip.address 
2012-11-11 15:55:05,294 DEBUG "PUT /v1/documents?uri=/example/test.xml HTTP/1.1" 401 211 
2012-11-11 15:55:05,430 DEBUG "PUT /v1/documents?uri=/example/test.xml HTTP/1.1" 201 0 

Wydaje serwer zawsze odbija pierwszą próbę uwierzytelniania, ale potem akceptuje drugi (?).

Z obiektu pliku (open ('TRB-1996-219.xml', 'rb')) przekazywane do danych, logfile pokazuje:

2012-11-11 15:50:54,309 INFO Starting new HTTP connection (1): my.ip.address 
2012-11-11 15:50:55,105 DEBUG "PUT /v1/documents?uri=/example/test.xml HTTP/1.1" 401 211 
2012-11-11 15:51:25,603 WARNING Retrying (0 attempts remain) after connection broken by 'BadStatusLine("''",)': /v1/documents?uri=/example/test.xml 

więc pierwsza próba jest zablokowany jak poprzednio, ale nie podjęto drugiej próby.

Według Martijna Pietersa (poniżej), drugi problem można wytłumaczyć błędnym serwerem (pusta linia). Zajrzę do tego, ale jeśli ktoś ma obejście (oprócz użycia curl), nie miałbym nic przeciwko temu.

I nadal jestem zaskoczony, że biblioteka żądań zachowuje się inaczej w przypadku małych ciągów i obiektów plików. Czy obiekt plików nie jest serializowany, zanim trafi on na serwer?

Odpowiedz

9

Aby umieścić duże pliki, nie czytaj ich w pamięci. Wystarczy przekazać plik jako słowa kluczowego data:

xmlfile = open('trb-1996-219.xml', 'rb') 
headers = {'content-type': 'application/xml'} 
r = requests.put(url, data=xmlfile, headers=headers, auth=HTTPDigestAuth("*", "*")) 

Ponadto pan otwierania pliku jako Unicode (dekodowanie go z UTF-8). Ponieważ będziesz wysyłać go do zdalnego serwera, potrzebujesz surowych bajtów, a nie wartości Unicode, a powinieneś otworzyć plik jako plik binarny.

+0

Dzięki za szybką odpowiedź. Rozwiązanie to rozwiązało UnicodeEncodeError, ale wprowadziło błąd ConnectionError: MaxRetryError. A serwer nie jest wyłączony, ponieważ mogę przesłać plik z curl. –

+0

@M_breeb: Musisz użyć modułu 'logging', aby dowiedzieć się, dlaczego tak się dzieje; próby połączenia z serwerem z jakiegoś powodu uległy awarii, * zanim * będzie mógł podać dane. Pula połączeń 'urllib3' ponawia próbę połączenia i rejestruje nieudane połączenie za każdym razem z modułem' logging'. –

+0

'importowanie rejestrowania', a następnie' logging.basicConfig() 'jest najbardziej podstawową metodą szybkiego uzyskania tego wyniku. –

1

Uwierzytelnianie szyfrowane zawsze wymaga podania co najmniej dwóch żądań na serwer. Pierwsze żądanie nie zawiera żadnych danych uwierzytelniających. To pierwsze żądanie zakończy się niepowodzeniem z kodem odpowiedzi 401 "Wymagana autoryzacja" i wyzwaniem podsumowania (zwanym przeczeniem), które będzie używane do mieszania hasła itp. (Dokładne dane nie mają tutaj znaczenia). Służy to do wysłania drugiego żądania do serwera zawierającego twoje poświadczenia zakotwiczone w wyzwaniu.

Problem polega na tym dwuetapowym uwierzytelnianiu: Twój duży plik został już wysłany z pierwszym nieautoryzowanym żądaniem (wysłanie na próżno), ale na drugim żądanie obiekt pliku znajduje się już w pozycji EOF. Ponieważ rozmiar pliku został również wysłany w nagłówku Content-length drugiego żądania, powoduje to, że serwer czeka na plik, który nigdy nie zostanie wysłany.

Można go rozwiązać za pomocą sesji żądań, a następnie złożyć proste żądanie uwierzytelnienia (na przykład żądanie GET). Następnie wykonaj drugie żądanie PUT zawierające rzeczywistą ładowność za pomocą tego samego kwestionariusza z pierwszego żądania.

sess = requests.Session() 
sess.auth = HTTPDigestAuth("*", "*") 
sess.get(url) 
headers = {'content-type': 'application/xml'} 
with codecs.open('trb-1996-219.xml', 'r', 'utf-8') as xmlfile: 
    sess.put(url, data=xmlfile, headers=headers) 
Powiązane problemy