2015-10-01 5 views
6

Der folgende Code sollte in Python 2.7 und Python 3.x ausgeführt werden können.Parsen Sie mehrteilige/Formulardaten mit cgi.FieldStorage; Keine Schlüssel

from __future__ import unicode_literals 
from __future__ import print_function 

import cgi 
try: 
    from StringIO import StringIO as IO 
except ImportError: 
    from io import BytesIO as IO 

body = """ 
--spam 
Content-Disposition: form-data; name="param1"; filename=blob 
Content-Type: binary/octet-stream 

value1 
--spam-- 
""" 

parsed = cgi.FieldStorage(
    IO(body.encode('utf-8')), 
    headers={'content-type': 'multipart/form-data; boundary=spam'}, 
    environ={'REQUEST_METHOD': 'POST'}) 

print([key for key in parsed]) 

In Python 2.7 es läuft gut, und es gibt ['param1']. In Python 3.4 gibt es jedoch [None] aus.

Ich kann FieldStorage nicht bekommen, um ein verwendbares Ergebnis in Python 3 zu erhalten. Ich vermute, dass etwas intern geändert wurde und ich es jetzt falsch benutze. Aber ich kann nicht herausfinden, was. Jede Hilfe wird geschätzt.

Antwort

3

wird identisch Ihr Skript funktioniert Diese Änderungen sowohl in Python 2.7.x und 3.4.x: (: Python 2.7.x: FS27, Python 3.4.x: ich diese Abkürzungen für cgi.FieldStorage() verwenden FS34)

- Während FS27 die Newline vor der Grenze richtig behandelt, das ist nicht der Fall mit FS34 so ist die Lösung mit Grenze (spam) direkt zu starten.

body = """--spam 
Content-Disposition: form-data; name="param1"; filename=blob 
Content-type: binary/octet-stream 

value1 
--spam-- 
""" 

- Zitiert aus cgi.pysource (in Definition Anmerkungen der FS34):

Argumente, die alle optional:

fp: Dateizeiger; default: sys.stdin.buffer (nicht verwendet, wenn die Anforderung GET-Methode ist)

 Can be : 
     1. a TextIOWrapper object 
     2. an object whose read() and readline() methods return bytes 

Der graue Teil ist in FS27 Definition nicht vorhanden ist, so sind die meisten der Unterschiede zwischen FS27 und FS34 liegen in der Handhabung von Strings (FS27) und binäre Ströme (FS34).

In diesem Zusammenhang FS34 kann leicht die Semantik des geparsten Objekts durcheinander bringen, es sei denn, es gibt richtige Anweisungen, wie dies richtig zu behandeln ist. Anscheinend ist der headers Wörterbucheintrag 'content-type': 'multipart/form-data; boundary=spam' nicht genug; Sie müssen die Informationen zur Nachrichtenlänge angeben.

Sie können dies erreichen, effektiv, durch einen zweiten Eintrag in headers Zugabe:

headers={'content-type': 'multipart/form-data; boundary=spam;', 
'content-length': len(body)} 

wo der Wert für die content-lengthSchlüssel ist die body Länge (einschließlich der Start-/Ende Grenzen).


Diese Modifikationen, kombiniert, zum gewünschten Ergebnis führen:

$ python script.py 
['param1'] 
$ python3 script.py 
['param1'] 

Als proof-of-concept, das sind die zurück parsed Objekte von beiden FS27 und FS34:

... 
print(parsed) 
... 

ergibt:

FieldStorage(None, None, [FieldStorage('param1', 'blob', 'value1')]) 

für FS27 und

FieldStorage(None, None, [FieldStorage('param1', 'blob', b'value1')]) 

für FS34.

0

In beiden Python 2.7 und Python 3.5 (nicht in Python 3.4 arbeiten aus irgendeinem Grund) wird die gewünschte Ausgabe von Content-Length der Antwort Körper Zugabe zurückgegeben:

body = """ 
--spam 
Content-Disposition: form-data; name="param1"; filename=blob 
Content-Length: 6 
Content-Type: binary/octet-stream 

value1 
--spam-- 
""" 
Verwandte Themen