Saya sedang membangun API tenang yang mendukung antrian tugas yang sudah berjalan lama untuk penanganan akhirnya.
Alur kerja khas untuk API ini adalah:
- Pengguna mengisi formulir
- Klien memposting data ke API
- Pengembalian API 202 Diterima
- Klien mengalihkan pengguna ke URL unik untuk permintaan itu (
/results/{request_id}
) - ~ akhirnya ~
- Klien mengunjungi URL lagi, dan melihat hasilnya di halaman itu.
Masalah saya ada pada langkah 6. Setiap kali pengguna mengunjungi halaman, saya mengajukan permintaan ke API saya ( GET /api/results/{request_id}
). Idealnya, tugas sudah selesai sekarang, dan saya akan mengembalikan 200 OK dengan hasil tugas mereka.
Tetapi pengguna memaksa, dan saya berharap banyak refresh bersemangat, ketika hasilnya belum selesai diproses.
Apa pilihan terbaik saya untuk kode status untuk menunjukkan bahwa:
- permintaan ini ada,
- itu belum selesai,
- tetapi juga tidak gagal.
Saya tidak mengharapkan satu kode untuk mengkomunikasikan semua itu, tetapi saya menginginkan sesuatu yang memungkinkan saya melewati metadata alih-alih meminta klien mengharapkan konten.
Masuk akal untuk mengembalikan 202, karena itu tidak akan memiliki arti lain di sini: itu adalah GET
permintaan, jadi tidak ada yang mungkin "diterima." Apakah itu pilihan yang masuk akal?
Alternatif yang jelas untuk semua ini - yang berfungsi, tetapi mengalahkan satu tujuan kode status - akan selalu menyertakan metadata:
200 OK
{
status: "complete",
data: {
foo: "123"
}
}
...atau...
200 OK
{
status: "pending"
}
Kemudian sisi klien, saya akan (menghela napas) switch
pada response.data.status
untuk menentukan apakah permintaan tersebut selesai.
Apakah ini yang harus saya lakukan? Atau ada alternatif yang lebih baik? Ini terasa begitu Web 1.0 bagi saya.
POST
permintaan pertama terbuka. Masalah utama dengan polling panjang atau soket web adalah bahwa pengguna mungkin menutup browser dan kembali. Saya dapat membukanya lagi pada waktu itu (dan itulah yang saya lakukan), tetapi tampaknya lebih bersih untuk memiliki satu API untuk dipanggil sebelum saya membuka soket itu, karena ini merupakan kasus tepi untuk masalah yang muncul.Jawaban:
HTTP 202 Diterima (HTTP / 1.1)
Anda mencari
HTTP 202 Accepted
status. Lihat RFC 2616 :Pemrosesan HTTP 102 (WebDAV)
RFC 2518 menyarankan menggunakan
HTTP 102 Processing
:tetapi memiliki peringatan:
Saya tidak yakin bagaimana menafsirkan kalimat terakhir. Haruskah server menghindari pengiriman apa pun selama pemrosesan, dan hanya merespons setelah selesai? Atau itu hanya memaksa untuk mengakhiri respons hanya ketika pemrosesan berakhir? Ini bisa bermanfaat jika Anda ingin melaporkan kemajuan. Kirim HTTP 102 dan siram respons byte demi byte (atau baris demi baris).
Misalnya, untuk proses yang panjang tapi linier, Anda dapat mengirim seratus titik, membilas setiap karakter. Jika pihak klien (seperti aplikasi JavaScript) tahu bahwa ia harus mengharapkan tepat 100 karakter, itu dapat mencocokkannya dengan bilah kemajuan untuk ditampilkan kepada pengguna.
Contoh lain menyangkut proses yang terdiri dari beberapa langkah non-linear. Setelah setiap langkah, Anda dapat membuka pesan log yang pada akhirnya akan ditampilkan kepada pengguna, sehingga pengguna akhir dapat mengetahui bagaimana prosesnya.
Masalah dengan pembilasan progresif
Perhatikan bahwa meskipun teknik ini memiliki kelebihan, saya tidak akan merekomendasikannya . Salah satu alasannya adalah bahwa hal itu memaksa koneksi untuk tetap terbuka, yang bisa merugikan dalam hal ketersediaan layanan dan tidak skala dengan baik.
Pendekatan yang lebih baik adalah merespons dengan
HTTP 202 Accepted
dan membiarkan pengguna untuk kembali kepada Anda nanti untuk menentukan apakah pemrosesan berakhir (misalnya dengan memanggil berulang kali URI yang diberikan seperti/process/result
yang akan merespons dengan HTTP 404 Tidak Ditemukan atau Konflik HTTP 409 hingga proses selesai dan hasilnya siap), atau beri tahu pengguna ketika pemrosesan selesai jika Anda dapat memanggil klien kembali misalnya melalui layanan antrian pesan ( misalnya ) atau WebSockets.Contoh praktis
Bayangkan sebuah layanan web yang mengkonversi video. Titik masuknya adalah:
yang mengambil file video dari permintaan HTTP dan melakukan sihir dengannya. Mari kita bayangkan bahwa sihir itu intensif CPU, jadi itu tidak dapat dilakukan secara real-time selama transfer permintaan. Ini berarti bahwa setelah file ditransfer, server akan merespons dengan
HTTP 202 Accepted
beberapa konten JSON, yang berarti “Ya, saya mendapatkan video Anda, dan saya sedang mengerjakannya; itu akan siap di suatu tempat di masa depan dan akan tersedia melalui ID 123. "Klien memiliki kemungkinan untuk berlangganan antrian pesan untuk diberi tahu ketika pemrosesan selesai. Setelah selesai, klien dapat mengunduh video yang diproses dengan masuk ke:
yang mengarah ke
HTTP 200
.Apa yang terjadi jika klien menanyakan URI ini sebelum menerima pemberitahuan? Nah, server akan merespons
HTTP 404
karena, memang, videonya belum ada. Saat ini mungkin disiapkan. Itu mungkin tidak pernah diminta. Mungkin ada beberapa waktu di masa lalu dan dihapus kemudian. Yang penting adalah bahwa video yang dihasilkan tidak tersedia.Sekarang, bagaimana jika klien tidak hanya peduli tentang video akhir, tetapi juga tentang kemajuan (yang akan menjadi lebih penting jika tidak ada layanan antrian pesan atau mekanisme serupa)?
Dalam hal ini, Anda dapat menggunakan titik akhir lain:
yang akan menghasilkan respons yang mirip dengan ini:
Melakukan permintaan berulang kali akan menunjukkan kemajuan sampai:
Sangat penting untuk membuat perbedaan antara ketiga jenis permintaan:
POST /video/convert
mengantri tugas. Ini harus dipanggil hanya sekali: memanggilnya lagi akan mengantri tugas tambahan.GET /video/download/123
menyangkut hasil operasi: sumber daya adalah video. Pemrosesan — itulah yang terjadi di bawah tenda untuk menyiapkan hasil aktual sebelum permintaan dan secara independen terhadap permintaan — tidak relevan di sini. Itu dapat dipanggil sekali atau beberapa kali.GET /video/status/123
menyangkut pemrosesan per se . Itu tidak mengantri apa pun. Itu tidak peduli dengan video yang dihasilkan. Sumber daya adalah proses itu sendiri. Itu dapat dipanggil sekali atau beberapa kali.sumber
GET
? Itu tentu pilihan yang tepat untuk inisialPOST
, itulah sebabnya saya menggunakannya. Tetapi tampaknya sangat mencurigakan bagi yangGET
mengatakan "diterima" ketika tidak menerima apa pun dari permintaan khusus itu.POST
naik pekerjaan yang harus antri, lalu sayaGET
hasilnya, berpotensi setelah klien menutup sesi. Sebuah 404 adalah sesuatu yang saya sudah dipertimbangkan juga, tetapi tampaknya salah, karena permintaan yang ditemukan, itu hanya belum selesai. Itu akan menunjukkan kepada saya bahwa pekerjaan yang antri tidak ditemukan, yang merupakan situasi yang sangat berbeda.GET
bagian itu, jangan menganggapnya sebagai permintaan yang tidak lengkap , tetapi sebagai permintaan untuk mendapatkan hasil operasi . Misalnya, jika saya memberi tahu Anda untuk mengonversi video dan Anda perlu waktu lima menit untuk melakukannya, meminta video yang dikonversi dua menit kemudian akan menghasilkan HTTP 404, karena video tersebut belum ada di sana. Meminta kemajuan operasi itu sendiri, di sisi lain, mungkin akan menghasilkan HTTP 200 yang berisi jumlah byte yang dikonversi, kecepatan, dll.Ini cara yang tepat untuk pergi. Status sumber daya dalam kaitannya dengan log khusus domain (alias logika bisnis) adalah masalah untuk tipe konten representasi sumber daya.
Ada dua konsep perbedaan yang disatukan di sini yang sebenarnya berbeda. Salah satunya adalah status transfer negara antara klien dan server sumber daya, dan yang lainnya adalah keadaan sumber daya itu sendiri dalam konteks apa pun yang dilakukan domain bisnis terhadap berbagai status sumber daya itu. Yang terakhir tidak ada hubungannya dengan kode status HTTP.
Ingat kode status HTTP sesuai dengan transfer negara antara klien dan server sumber daya yang ditangani, secara independen ke setiap detail sumber daya itu. Ketika Anda
GET
sumber daya klien Anda meminta server untuk representasi dari sumber daya dalam keadaan saat ini. Itu bisa menjadi gambar burung, itu bisa menjadi dokumen Word, itu bisa menjadi temp luar saat ini. Protokol HTTP tidak peduli. Kode status HTTP sesuai dengan hasil permintaan itu. ApakahPOST
dari klien ke server mentransfer sumber daya ke server, di mana server kemudian memberikan URL yang dapat dilihat klien? Iya? Maka itu adalah201 Created
respons.Sumber daya bisa berupa pemesanan maskapai yang saat ini dalam kondisi 'untuk ditinjau'. Atau bisa juga pesanan pembelian produk yang dalam kondisi 'disetujui'. Status tersebut adalah spesifik domain dan bukan tentang protokol HTTP. Protokol HTTP berkaitan dengan transfer sumber daya antara klien dan server.
Maksud dari REST dan HTTP adalah bahwa protokol tidak memperhatikan dirinya sendiri dengan rincian sumber daya. Ini sengaja, tidak berkaitan dengan masalah khusus domain sehingga dapat digunakan tanpa harus tahu apa-apa tentang masalah khusus domain. Anda tidak menafsirkan ulang arti kode status HTTP dalam setiap konteks yang berbeda (sistem pemesanan maskapai, sistem pemrosesan bayangkan, sistem keamanan video, dll.).
Hal-hal khusus domain adalah untuk klien dan server untuk mencari tahu di antara mereka sendiri berdasarkan pada
Content Type
sumber daya. Protokol HTTP agnostik untuk ini.Adapun cara klien mengetahui bahwa sumber daya Permintaan telah berubah status, pemungutan suara adalah taruhan terbaik Anda karena tetap mengendalikan di klien dan tidak menganggap koneksi tidak terputus. Terutama jika itu akan berpotensi berjam-jam sampai negara berubah. Bahkan jika Anda mengatakan persetan dengan REST Anda hanya akan menjaga koneksi tetap terbuka, menjaganya tetap terbuka selama berjam-jam dan dengan asumsi tidak ada yang salah akan menjadi ide yang buruk. Bagaimana jika pengguna menutup klien atau jaringan padam. Jika rinciannya adalah jam, klien hanya dapat meminta status setiap beberapa menit sampai Permintaan berubah dari 'menunggu' menjadi 'selesai'.
Harapan itu membantu memperjelas hal-hal
sumber
Saya menemukan saran dari blog ini masuk akal: REST dan pekerjaan jangka panjang .
Untuk meringkas:
sumber
Kode Status HTTP untuk Sumber Daya belum tersedia menyarankan untuk mengembalikan respons konflik 409, daripada respons 404, dalam hal sumber daya tidak ada karena sedang dibuat.
Dari spesifikasi w3 :
Ini agak canggung, karena kode 409 "hanya diperbolehkan dalam situasi di mana diharapkan pengguna dapat menyelesaikan konflik dan mengirim kembali permintaan." Saya sarankan badan respons menyertakan pesan (mungkin dalam beberapa format respons yang cocok dengan API Anda yang lain) seperti, "Sumber daya ini sedang dibuat. Ini dimulai pada [WAKTU] dan diperkirakan selesai pada [WAKTU]. Silakan coba lagi nanti."
Perhatikan bahwa saya hanya akan menyarankan pendekatan 409 jika sangat mungkin bahwa pengguna yang meminta sumber daya juga adalah pengguna yang memprakarsai generasi sumber daya itu. Pengguna yang tidak terlibat dengan pembuatan sumber daya akan menemukan kesalahan 404 kurang membingungkan.
sumber