Requests: Hasilkan posting multi-bagian tanpa file

Dibuat pada 3 Jan 2013  ·  36Komentar  ·  Sumber: psf/requests

Saat ini, satu-satunya cara untuk memiliki permintaan formulir multi-bagian adalah r = requests.post(url, data=payload, files=files)
yang mungkin memiliki komponen

Content-Disposition: form-data; name="file"; filename="filename.txt"
Content-Type: text/plain

content
--3eeaadbfda0441b8be821bbed2962e4d--

Namun, saya mengalami kasus di mana posting harus dalam format multi-bagian tanpa file terkait, seperti:

Content-Disposition: form-data; name="key1"

value1
--3eeaadbfda0441b8be821bbed2962e4d

tetapi yang terakhir tidak mungkin dihasilkan tanpa yang pertama.

Mungkin kita bisa menambahkan flag seperti r = requests.post(url, data=payload, multipart=True) yang memaksa sebuah postingan menjadi multipart, bahkan tanpa file.

Saya senang bekerja untuk mengimplementasikan ini jika kedengarannya seperti ide yang bagus.

Semua 36 komentar

Ini telah dibahas sebelumnya. Ini akan mewakili perubahan signifikan pada API yang saya tidak yakin @kennethreitz akan menyukainya.

Secara pribadi, saya akan lebih suka mengekspos fungsi untuk menghasilkan data multi-bagian dari kamus (daftar tupel, dll) di API sehingga pengguna dapat menggunakannya dan hanya meneruskan data yang dihasilkan ke permintaan. Seolah-olah, jika mereka tidak menggunakan file, seharusnya tidak ada hit memori yang besar, tetapi meskipun demikian, mereka sudah memiliki satu string besar dalam memori, yang kedua tidak akan benar-benar membunuh mereka dan itu akan menjadi kesalahan mereka, bukan milik kita. .

Mungkin @kennethreitz akan lebih menerima solusi kedua. Saya tidak berpikir itu cocok dengan filosofi desain permintaan dan akan sangat aneh mengingat sisa API, tetapi _shrug_ siapa yang tahu.

Memang, API saat ini tidak mendukung pengiriman data multi-bagian selain file dan ini adalah hal yang buruk. Lihat edisi #935 dan shazow/urllib3/issues/120

Mungkin saya kehilangan sesuatu, tetapi perubahannya tampak agak kecil bagi saya. Saya melakukan fork repositori dan mengusulkan perubahan dalam versi saya di sini: https://github.com/spacecase/requests/commit/45b0b3ce1e76b241b323570a5fc88ae2089c3c3d
(jika ada cara yang lebih baik untuk melakukan ini, beri tahu saya? Saya agak baru di github).

Mungkin perlu beberapa unittests dan akan membutuhkan perubahan dalam docstring di api.py, tetapi apakah hal seperti ini masuk akal?

Masalah dengan perubahan tersebut bukanlah karena rumit untuk diterapkan, melainkan karena perbedaan dalam API. Saya agak ragu-ragu dalam diskusi yang sedang berlangsung ini: Saya pikir mungkin akan berguna untuk memiliki cara yang baik untuk mengunggah data formulir multi-bagian, tetapi saya juga berpikir bahwa files API saat ini sangat bagus . Saya _tidak_ berpikir bahwa menambahkan multipart ke Request API adalah cara yang harus dilakukan.

Sejujurnya, saya pribadi lebih suka mengontrolnya melalui tajuk tipe konten tetapi itu kemungkinan 100x lebih rawan kesalahan dan membingungkan pengguna baru daripada yang kami lakukan saat ini. Saya berada di pagar tentang hal ini juga, tapi saya masih akan berbuat salah di sisi tidak melakukan ini.

Mengapa? Jika kami menerima permintaan fitur ini, kemungkinan besar seseorang akan mengeluh karena tidak memiliki parameter json. Dan saya yakin orang lain dapat membuat lebih banyak parameter yang ingin mereka tambahkan. Seperti sekarang, API melakukan persis seperti yang seharusnya dan memiliki sedikit atau tanpa kruft. Salah satu cara untuk melihat ini adalah KISS. Ini membuat permintaan dan pengembalian menjadi objek hebat yang membuat penggunaan respons menjadi mudah dan alami. Itu melakukan apa yang diiklankan dan Anda melakukan sisanya. Itu mengiklankan pengkodean multi-bagian dan melakukannya melalui desain yang didokumentasikan. Ini mungkin terlihat canggung tetapi didokumentasikan dan berhasil.

_(...) seseorang akan mengeluh karena tidak memiliki parameter json_

Tidak akan ada alasan untuk keluhan seperti itu karena json adalah subtipe dari application jenis media ( rfc4627 ) bukan multipart jenis media ( httpbis draft 21 )

_Mungkin terlihat canggung (...)_

Ini canggung padahal seharusnya tidak.

Setelah membaca komentar sebelumnya, saya ingin menegaskan kembali posisi saya: multipart/form-data adalah tipe MIME multibagian paling umum yang saat ini digunakan (perlu kutipan :)) dan tidak mendukungnya adalah kelalaian besar.

@ piotr-dobrogost: Terlepas dari apa yang saya katakan di atas, saya tidak menemukan argumen yang baru saja Anda buat sedikit menarik.

Permintaan tidak mendukung jenis MIME, ini mendukung kasus penggunaan. Sudut pandang ini membuat kedua komentar Anda di atas tampak aneh. Misalnya, keluhan tentang tidak memiliki parameter JSON adalah karena mengunggah data berformat JSON sangat umum - mungkin lebih umum di antara pengguna Permintaan daripada mengunggah data multi-file non-file. Berdebat bahwa kami tidak akan menyediakannya karena 'kami hanya subtipe kasus khusus dari multipart ' sepertinya hal yang aneh untuk dikatakan.

Terlepas dari itu, inti masalahnya adalah ini: API adalah inti dari perpustakaan ini. Jika Anda tidak dapat menemukan cara _indah_ untuk mengimplementasikan fungsi ini, itu tidak akan terjadi.

Tidak akan ada alasan untuk keluhan seperti itu [sic]

@piotr-dobrogost Anda memiliki lebih banyak harapan untuk masa depan pengembang daripada saya. Di luar itu, parameter yang diminta tidak tepat. Itu perlu disebut sesuatu yang lebih seperti form_data daripada multipart . Seperti yang Anda perhatikan, (walaupun secara tidak langsung) multipart dapat merujuk ke banyak jenis media yang berbeda.

Ini canggung padahal seharusnya tidak.

Tidak semua hal bisa elegan (bahkan dengan python).

dan tidak mendukungnya

Tapi itu didukung. Tapi selain itu, kita memiliki data untuk application/x-www-form-urlencoded , files (atau files+data ) untuk multipart/form-data , mengapa kita membutuhkan parameter lain hanya dengan multipart/form-data saat kita memilikinya?

Anda tidak perlu menggunakan kombinasi data dan files untuk mendapatkan hasil yang diinginkan. Anda dapat melakukan sesuatu yang mirip dengan: requests.post('http://example.com/', files=[('key1', 'param1'), ('key2', 'param2')]) tanpa memiliki file aktual di sana.

Dan jika kita tepatnya, form_data mungkin tidak sepenuhnya jelas, jadi mengapa tidak menggunakan parameter multipart_form_data , tapi sekarang itu juga canggung. Ini eksplisit, ya, dan PEP 8 meminta eksplisit, tetapi perilaku yang ada didokumentasikan dengan baik . Jika @kennethreitz memutuskan untuk menerima permintaan fitur ini, semua parameter yang perlu dilakukan adalah bertindak sebagai alias untuk parameter files. Tetapi mengingat perilaku itu sudah didukung, saya pikir itu tidak perlu.

@sigmavirus24 dan @Lukasa menyimpulkan ini dengan sempurna.

@piotr-dobrogost kontribusi Anda dihargai, tetapi bukan nada bicara Anda. Tolong berhenti membuat pernyataan tegas terhadap proyek kami dan tujuannya.

Dari sudut pandang saya, cukup membuat frustrasi bahwa permintaan sudah memiliki dukungan untuk posting multi-bagian, tetapi tidak memberi pengguna akses ke sana tanpa menggunakan file. Saran @ sigmavirus24 untuk hanya menempelkan file di sana tidak memadai. Aplikasi web tempat saya bekerja akan mengembalikan kode kesalahan jika sesuatu seperti ini dicoba.

Saya menduga ini akan terus menjadi masalah bagi pengguna di masa depan, dan saya sedikit bingung mengapa sepertinya tidak ada upaya untuk mengatasi hal ini.

Lihat tanggapan saya untuk #935

Oh terima kasih. Saya menantikannya!

@Lukasa

_Permintaan tidak mendukung jenis MIME, ini mendukung kasus penggunaan._

Mengirim data multipart/form-data adalah kasus penggunaan yang umum.

_(...) mengunggah data berformat JSON sangat umum (...)_

Kami tidak dapat membandingkan pengiriman json dengan pengiriman multipart/form-data . Mengirim json itu mudah; anda mengatur Content-type , menyandikan data dalam satu baris menggunakan modul bawaan dan hanya itu. Mengirim multipart/form-data lebih rumit karena isi permintaan harus memiliki struktur khusus. Dengan kata lain mengirim json agak transparan seperti halnya HTTP tetapi mengirim multipart/form-data tidak. Karena Permintaan adalah perpustakaan HTTP, ia harus berhati-hati dalam membuat struktur seperti itu.

_Jika Anda tidak dapat menemukan cara yang indah untuk mengimplementasikan fungsi ini, itu tidak akan terjadi._

Memiliki parameter files untuk mengirim multipart/form-data yang TIDAK ADA hubungannya dengan file sama sekali tidak indah (itu jelek), namun entah bagaimana berhasil masuk ke basis kode :). Menghasilkan sesuatu yang kurang jelek sangat mudah :)

@sigmavirus24

_(...) tetapi perilaku yang ada didokumentasikan dengan baik._

Tidak ada jumlah dokumentasi yang membuat API bagus dari API yang buruk. Semakin baik API, semakin sedikit dokumentasi yang dibutuhkan.

_Anda dapat melakukan sesuatu yang mirip dengan (...)_

Benar, tetapi ini sangat menyesatkan dan tidak intuitif. Saya menjelaskan apa yang salah dengan menggunakan param files untuk ini di komentar saya sebelumnya .

Intinya: untuk menghasilkan sesuatu yang lebih baik, kita harus mengakui bahwa api saat ini buruk sehubungan dengan pengiriman data multipart/form-data .

@spacecase

_Dari sudut pandang saya, cukup frustasi bahwa permintaan sudah memiliki dukungan untuk posting multi-bagian, tetapi tidak memberikan akses pengguna ke sana tanpa menggunakan file_

Saya setuju dan itulah mengapa saya membuat edisi #935.

Masalah ini ditutup.

Maafkan saya @kennethreitz tapi @spacecase saya tidak menggunakan file di mana pun dalam contoh itu. Saya menggunakan parameter files untuk melakukan apa yang Anda inginkan. Seandainya saya menggunakan file, Anda akan melihat open('filename') .

@sigmavirus24 , Sayangnya bukan itu yang saya inginkan. Ini bukan masalah apakah klien membaca dari file atau tidak. Itu yang diberitahukan ke server. Dalam contoh Anda, badan pos adalah

Content-Disposition: form-data; name="key1"; filename="key1"
Content-Type: application/octet-stream

param1
--2f8732ee35564115a6c6e0c1032773e8
Content-Disposition: form-data; name="key2"; filename="key2"
Content-Type: application/octet-stream

param2
--2f8732ee35564115a6c6e0c1032773e8--

Perhatikan penggunaan filename= . Ini memberi tahu server bahwa file sedang dikirim. Di aplikasi web saya bekerja dengan perilaku yang salah ini menghasilkan kesalahan.

Maaf, tetapi karena Anda begitu lancang untuk memberi tahu saya bahwa itulah yang saya inginkan, itu menyinggung perasaan saya. Saya datang untuk menawarkan ide dan bantuan, dan sepertinya Anda tidak menginginkan keduanya dalam kasus ini. Tidak apa-apa, tapi tolong jangan membuatku merasa direndahkan.

Hm, sepertinya aku salah mengingat perilakunya. Maaf tentang itu. Sama sekali bukan niat saya untuk menyinggung Anda atau membuat Anda merasa direndahkan. Itu pasti cukup untuk membuat saya bergoyang untuk membutuhkan cara yang lebih baik untuk menangani multipart/form-data , tetapi untuk saat ini saya masih tidak setuju bahwa ide untuk API sama sekali tidak elegan.

@spacecase silakan lihat tanggapan saya untuk #935. Hal-hal akan lebih baik. Umpan balik Anda penting dan sangat dihargai. :)

@spacecase sebagai isyarat untuk menunjukkan bahwa pendapat Anda penting, lihat sigmavirus24/requests-data-schemes sebagai langkah stop-gap. Anda harus menyetel tajuk Content-Type Anda sendiri, tetapi itu mungkin sedikit mengganggu.

Terima kasih @sigmavirus24 , saya akan mencobanya. Sepertinya itu akan berhasil.
Saya menghargai bahwa Anda tidak bermaksud menyinggung saya. Saya merasa lebih baik tentang itu dan saya tidak menentang Anda atau proyek itu.

Ya, sepertinya saya dianggap kurang ajar bagi sebagian orang, jadi saya rasa saya perlu memperbaiki apa yang saya tulis di internet. Saya tidak memahaminya dan orang lain setuju dengan saya, tetapi saya sedang mengusahakannya. Saya kira saya hanya perlu ukuran sampel yang cukup besar untuk menyadari apa yang menyinggung orang tanpa niat saya (selain saya mempermalukan diri sendiri dengan mengingat sesuatu yang bekerja dengan cara yang tidak).

Saya memiliki file dan beberapa nilai kunci untuk diposting. Jadi apa cara yang benar untuk mengirim permintaan formulir mutilpart seperti itu? Saya harap Anda dapat membantu saya.

Content-Disposition: form-data; name="up"; filename="aa.PNG"
Content-Type: image/png

file data
---------------------------7dee5302248e
Content-Disposition: form-data; name="exp"


-----------------------------7dee5302248e
Content-Disposition: form-data; name="ptext"

text
-----------------------------7dee5302248e
Content-Disposition: form-data; name="board"

DV_Studio
-----------------------------7dee5302248e--

I tried this way but only got a 504 error.
myfile=[('file',open('bb.jpg')),('exp','python'),('ptext',''),('board','DV_Studio')]
r = requests.post(url,files=myfile)

@deerstalker untuk pertanyaan silakan gunakan StackOverflow . Untuk menjawab pertanyaan Anda, ada proyek yang sedang berjalan untuk mengatasi masalah ini sigmavirus24/requests-toolbelt

Perhatikan juga bahwa saya telah menjawab pertanyaan ini sebelumnya di StackOverflow, seperti yang Anda lihat di sini .

Saya memiliki masalah yang sama dalam menghasilkan posting multi-bagian tanpa file. Saat ini, tidak ada bedanya jika Anda melakukan requests.post(url, data=data_dict) atau requests.post(url, data=data_dict, files={}) . Namun, karena kata kunci files default ke None , kita harus dapat memiliki dua perilaku yang berbeda. multipart/form-data ketika files={} ditentukan, dan application/x-www-form-urlencoded jika tidak.

Apakah saya melewatkan sesuatu?

@jwoillez Apakah Anda mengikuti tautan stack overflow yang saya posting?

Saya kira begitu, tetapi jawaban Anda di sana berkaitan dengan Multipart POST dengan satu file. Saya kembali ke masalah awal: Multipart POST tanpa file.

Objek file diperbolehkan menjadi string. =) Itu akan memberi Anda informasi yang Anda inginkan.

Tetapi jika saya mengikuti saran Anda, bukankah saya akan berakhir dengan sesuatu seperti ini:

Content-Disposition: form-data; name="file"; filename="filename.txt"
Content-Type: text/plain

content
--3eeaadbfda0441b8be821bbed2962e4d--

di mana content adalah string yang Anda undang untuk saya gunakan alih-alih file?

Saya benar-benar mengejar ini saja:

Content-Disposition: form-data; name="key1"

value1
--3eeaadbfda0441b8be821bbed2962e4d

Bidang di Tuple yang tidak Anda inginkan dapat dibiarkan sebagai default:

files = {'name': ('', 'content')}

Di masa mendatang, harap arahkan pertanyaan Anda ke StackOverflow. Semua pengelola secara teratur melacaknya, dan ini adalah tempat yang lebih tepat untuk mengajukan pertanyaan-pertanyaan ini.

Itu jawaban yang saya cari, terima kasih. Maaf untuk kebisingan.

Mungkin satu pertanyaan terakhir, apakah yang berikut ini mungkin (nama file kosong yang ditentukan, konten kosong)?

Content-Disposition: form-data; name="file"; filename=""
Content-Type: text/plain


--3eeaadbfda0441b8be821bbed2962e4d--

Anda dapat memberikan konten kosong dengan menggunakan string kosong di bagian konten dari tuple. Anda tidak dapat memberikan nama file kosong literal, tetapi nama file yang tidak ada harus diperlakukan dengan cara yang persis sama.

Saya kadang-kadang perlu melakukan ini karena berbagai alasan aneh.
Saya menyarankan pendekatan ini untuk siapa pun yang ingin mempersenjatai API dengan kuat ke dalam kasus penggunaan ini:

class ForceMultipartDict(dict):
    def __bool__(self):
        return True


FORCE_MULTIPART = ForceMultipartDict()  # An empty dict that boolean-evaluates as `True`.


client.post("/", data={"some": "data"}, files=FORCE_MULTIPART)

Atau Anda dapat menggunakan sabuk alat dan tidak menggunakan peretasan.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat