Paging dalam Koleksi Istirahat


134

Saya tertarik untuk mengekspos antarmuka REST langsung ke koleksi dokumen JSON (pikirkan CouchDB atau Persevere ). Masalah yang saya hadapi adalah bagaimana menangani GEToperasi pada root collection jika koleksinya besar.

Sebagai contoh, anggap saya sedang mengekspos Questionstabel StackOverflow di mana setiap baris diekspos sebagai dokumen (bukan berarti ada tabel seperti itu, hanya contoh konkret dari kumpulan 'dokumen' yang cukup besar). Koleksi akan tersedia di /db/questionsdengan biasa CRUD api GET /db/questions/XXX, PUT /db/questions/XXX, POST /db/questionsadalah dalam bermain. Cara standar untuk mendapatkan seluruh koleksi adalah dengan GET /db/questionstetapi jika itu secara naif membuang setiap baris sebagai objek JSON, Anda akan mendapatkan unduhan yang cukup besar dan banyak pekerjaan di bagian server.

Solusinya, tentu saja, paging. Dojo telah memecahkan masalah ini di JsonRestStore - nya melalui ekstensi pintar yang sesuai dengan RFC2616 menggunakan Rangeheader dengan unit jangkauan khusus items. Hasilnya adalah 206 Partial Contentyang hanya mengembalikan kisaran yang diminta. Keuntungan dari pendekatan ini dibandingkan parameter kueri adalah ia meninggalkan string kueri untuk ... kueri (misalnya GET /db/questions/?score>200atau semacamnya, dan ya yang akan dikodekan %3E).

Pendekatan ini sepenuhnya mencakup perilaku yang saya inginkan. Masalahnya adalah bahwa RFC 2616 menetapkan bahwa pada respons 206 (penekanan saya):

The permintaan HARUS menyertakan Rentang sundulan lapangan ( bagian 14,35 ) menunjukkan kisaran yang diinginkan, dan MUNGKIN telah menyertakan header bidang Jika-Range ( bagian 14.27 ) untuk membuat permintaan bersyarat.

Ini masuk akal dalam konteks penggunaan standar tajuk tetapi menjadi masalah karena saya ingin respons 206 menjadi default untuk menangani klien naif / penjelajahan acak.

Saya telah membahas RFC secara mendetail mencari solusi tetapi tidak senang dengan solusi saya dan saya tertarik dengan SO yang menangani masalah tersebut.

Ide yang saya miliki:

  • Kembali 200dengan Content-Rangetajuk! - Saya tidak berpikir bahwa ini salah, tetapi saya lebih suka jika indikator yang lebih jelas bahwa responsnya hanya Konten Sebagian.
  • Kembali400 Range Required - Tidak ada kode respons 400 khusus untuk header yang diperlukan, jadi kesalahan default harus digunakan dan dibaca secara manual. Hal ini juga membuat eksplorasi melalui browser web (atau klien lain seperti Resty) lebih sulit.
  • Gunakan parameter kueri - Pendekatan standar, tetapi saya berharap untuk mengizinkan kueri ala Persevere dan ini memotong ruang nama kueri.
  • Kembali saja 206! - Saya pikir sebagian besar klien tidak akan panik, tetapi saya lebih suka tidak melawan HARUS di RFC
  • Perluas spesifikasi! Return266 Partial Content - Berperilaku persis seperti 206 tetapi sebagai respons atas permintaan yang HARUS TIDAK berisi Rangeheader. Saya pikir 266 cukup tinggi sehingga saya tidak akan mengalami masalah tabrakan dan itu masuk akal bagi saya, tetapi saya tidak jelas apakah ini dianggap tabu atau tidak.

Menurut saya ini adalah masalah yang cukup umum dan saya ingin melihat ini dilakukan secara de facto sehingga saya atau orang lain tidak menciptakan kembali kemudi.

Bagaimana cara terbaik untuk mengekspos koleksi lengkap melalui HTTP jika koleksinya besar?


21
Wow, itu adalah contoh bagus dari pertanyaan di mana pemikiran serius telah dilakukan sebelumnya.
Heiko Rupp

kemungkinan duplikat Pagination dalam aplikasi web REST
rds

2
Sejauh pendekatan Dojo dalam menggunakan header Range, meskipun Accept-Ranges memungkinkan ekstensi, dari semua yang saya tahu, EBNF untuk Range tidak: tools.ietf.org/html/rfc2616#section-14.35.2 . Spesifikasi menunjukkan di Range = "Range" ":" ranges-specifiermana yang terakhir di tools.ietf.org/html/rfc2616#section-14.35.1 dijelaskan hanya sebagai "byte-range-specifier" yang harus dimulai dengan "unit-byte" yang didefinisikan sebagai string "byte ".
Brett Zamir

2
The Content-RangeHeader berlaku untuk tubuh (dapat digunakan dengan permintaan ketika meng-upload file besar dll, atau untuk respon saat men-download). The Rangeheader digunakan untuk meminta kisaran tertentu. Seseorang harus menanggapi dengan 206saat Rangeheader dimasukkan dalam permintaan. Jika tidak, respons mungkin masih menyertakan Content-Rangeheader, tetapi kode respons harus seperti itu 200. Header ini sebenarnya tampak ideal untuk paging.
Stijn de Witt

1
Namun RFC 2616 sendiri mengatakan bahwa "implementasi HTTP / 1.1 MUNGKIN mengabaikan rentang yang ditentukan menggunakan unit lain." Jadi, apakah praktik yang baik menggunakan header Rentang untuk penomoran halaman? karena mungkin mengganggu interoperabilitas.
chetan choulwar

Jawaban:


23

Perasaan saya adalah bahwa ekstensi rentang HTTP tidak dirancang untuk kasus penggunaan Anda, dan karenanya Anda tidak boleh mencoba. Respons parsial menyiratkan 206, dan 206hanya boleh dikirim jika klien memintanya.

Anda mungkin ingin mempertimbangkan pendekatan yang berbeda, seperti yang digunakan di Atom (di mana representasi menurut desain mungkin parsial, dan dikembalikan dengan status 200, dan kemungkinan tautan halaman). Lihat RFC 4287 dan RFC 5005 .


14
Penggunaan Dojo sepenuhnya sesuai spesifikasi. Jika server tidak memahami itemsunit jangkauan, server akan mengembalikan respons penuh. Saya terbiasa dengan Atom tetapi itu bukan solusi umum untuk Rest paging. Ini bukan solusi untuk satu kasus, lebih dari apa solusi umum yang seharusnya. Tidak semua dokumen / koleksi sesuai dengan model Atom dan tidak ada alasan untuk memaksakannya kecuali diperlukan.
Karl Guertin

1
@Karl Setuju. Sayangnya ini adalah jawaban yang diterima, karena tampaknya banyak di komunitas yang sebenarnya merangkul Rangedan Content-Rangeuntuk tujuan paging.
Stijn de Witt

34

Saya tidak begitu setuju dengan beberapa dari kalian. Saya telah bekerja selama berminggu-minggu pada fitur ini untuk layanan REST saya. Apa yang akhirnya saya lakukan sangat sederhana. Solusi saya hanya masuk akal untuk apa yang disebut orang REST sebagai koleksi.

Klien HARUS menyertakan header "Range" untuk menunjukkan bagian mana dari koleksi yang dia butuhkan, atau siap untuk menangani kesalahan 413 REQUESTED ENTITY TOO LARGE ketika koleksi yang diminta terlalu besar untuk diambil dalam satu perjalanan pulang pergi.

Server mengirim respons 206 KONTEN SEBAGIAN, dengan header Rentang Konten yang menentukan bagian mana dari sumber daya yang telah dikirim, dan header ETag untuk mengidentifikasi versi koleksi saat ini. Saya biasanya menggunakan ETag seperti Facebook {last_modification_timestamp} - {resource_id}, dan saya menganggap bahwa ETag dari sebuah koleksi adalah sumber daya yang paling baru dimodifikasi di dalamnya.

Untuk meminta bagian tertentu dari sebuah koleksi, klien HARUS menggunakan header "Range", dan mengisi header "If-Match" dengan ETag dari koleksi yang diperoleh dari permintaan yang dilakukan sebelumnya untuk mendapatkan bagian lain dari koleksi yang sama. Oleh karena itu server dapat memverifikasi bahwa koleksi tidak berubah sebelum mengirim bagian yang diminta. Jika ada versi yang lebih baru, respons 412 PRECONDITION FAILED dikembalikan untuk mengundang klien mengambil koleksi dari awal. Ini diperlukan karena ini bisa berarti bahwa beberapa sumber daya mungkin telah ditambahkan atau dihapus sebelum atau setelah bagian yang saat ini diminta.

Saya menggunakan ETag / If-Match bersama-sama dengan Last-Modified / If-Unmodified-Because untuk mengoptimalkan cache. Browser dan proxy mungkin mengandalkan salah satu atau keduanya untuk algoritme caching mereka.

Saya pikir URL harus bersih kecuali untuk menyertakan kueri penelusuran / filter. Jika Anda memikirkannya, pencarian tidak lebih dari tampilan parsial dari sebuah koleksi. Alih-alih URL jenis cars / search? Q = BMW, kita seharusnya melihat lebih banyak cars? Manufacturer = BMW.


Apakah maksud Anda 416 "Rentang yang Diminta Tidak Memuaskan" atau "413" Meminta Entitas Terlalu Besar?

1
@Mohamed Saya pikir maksud Anda If-Unmodified-Since, yang sesuai dengan varian E-Tag If-Match, bukan If-Modified-Since. Karena itu, Anda mungkin juga mempertimbangkan untuk menghilangkan batasan ini, tergantung pada kasus penggunaan Anda. Misalkan Anda memiliki koleksi yang hanya tumbuh dari atas (seperti beberapa koleksi gaya "terbaru pertama"), hal terburuk yang dapat terjadi jika koleksi tersebut berubah di antara permintaan adalah bahwa pengguna yang membuka halaman melalui koleksi melihat entri dua kali. (Yang dengan sendirinya juga merupakan informasi yang berguna: Ini memberi tahu pengguna bahwa koleksi telah berubah)
Evgeniy Berezovsky

21
413 adalah "Entitas Permintaan Terlalu Besar", bukan "Entitas Permintaan Terlalu Besar". Ini berarti ukuran permintaan Anda, misalnya saat mengupload file, lebih besar dari yang ingin diproses server. Jadi menggunakannya untuk ini sepertinya tidak sepenuhnya tepat.
user247702

@Mohamed Saya tahu ini adalah pertanyaan lama, tetapi jika ETag dari sebuah koleksi adalah ETag dari sumber daya yang paling baru diubah koleksi tersebut, nilai mana dari tajuk If-Match yang harus digunakan saat memodifikasi satu sumber daya dalam koleksi? Menggunakan nilai ETag yang dikembalikan dengan koleksi salah karena klien dapat mengubah sumber daya meskipun dia tidak melihat status terakhir sumber daya.
Mickael Marrache

9
Saya sangat tidak setuju tentang penggunaan 413. Ini adalah kode kesalahan yang berarti bahwa klien mengirimkan sesuatu yang ditolak oleh server karena ukurannya. Bukan sebaliknya! Lihat tools.ietf.org/html/rfc7231#section-6.5.11 (perhatikan bahwa dikatakan request payload. Not response payload)!
exhuma

7

Anda masih dapat kembali Accept-Rangesdan Content-Rangesdengan 200kode tanggapan. Kedua header respons ini memberi Anda informasi yang cukup untuk menyimpulkan informasi yang sama yang diberikan 206kode respons secara eksplisit.

Saya akan menggunakan Rangeuntuk pagination, dan membuatnya hanya mengembalikan a 200untuk dataran GET.

Ini terasa 100% tenang dan tidak membuat penjelajahan menjadi lebih sulit.

Sunting: Saya menulis entri blog tentang ini: http://otac0n.com/blog/2012/11/21/range-header-i-choose-you.html


5

Jika ada lebih dari satu halaman tanggapan, dan Anda tidak ingin menawarkan seluruh koleksi sekaligus, apakah itu berarti ada beberapa pilihan?

Atas permintaan ke /db/questions, kembalikan 300 Multiple Choicesdengan Linkheader yang menentukan cara membuka setiap halaman serta objek JSON atau halaman HTML dengan daftar URL.

Link: <>; rel="http://paged.collection.example/relation/paged"
Link: <>; rel="http://paged.collection.example/relation/paged"
...

Anda akan memiliki satu Linktajuk untuk setiap halaman hasil (string kosong berarti URL saat ini, dan URL sama untuk setiap halaman, hanya diakses dengan rentang yang berbeda), dan hubungannya didefinisikan sebagai hubungan khusus untuk Linkspesifikasi yang akan datang . Hubungan ini akan menjelaskan kebiasaan Anda 266, atau pelanggaran Anda terhadap 206. Header ini adalah versi Anda yang dapat dibaca mesin, karena semua contoh Anda memerlukan klien yang memahami.

(Jika Anda tetap menggunakan rute "range", saya yakin 2xxkode pengembalian Anda sendiri , seperti yang Anda gambarkan, akan menjadi perilaku terbaik di sini. Anda diharapkan melakukan ini untuk aplikasi Anda dan ["kode status HTTP dapat diperpanjang. "], dan Anda punya alasan bagus.)

300 Multiple Choicesmengatakan Anda HARUS juga memberikan tubuh cara untuk dipilih oleh agen pengguna. Jika klien Anda mengerti, itu harus menggunakan Linkheader. Jika pengguna yang menjelajah secara manual, mungkinkah laman HTML dengan tautan ke sumber daya root "halaman" khusus yang dapat menangani perenderan laman tersebut berdasarkan URL? /humanpage/1/db/questionsatau sesuatu yang mengerikan seperti itu?


Komentar di posting Richard Levasseur mengingatkan saya pada opsi tambahan: Acceptheader (bagian 14.1). Kembali ketika spesifikasi oEmbed keluar, saya bertanya-tanya mengapa itu tidak dilakukan sepenuhnya menggunakan HTTP, dan menulis alternatif menggunakan mereka.

Pertahankan 300 Multiple Choices, Linkheader dan halaman HTML untuk HTTP naif awal GET, tetapi alih-alih menggunakan rentang, buat hubungan halaman baru Anda menentukan penggunaan Acceptheader. Permintaan HTTP Anda berikutnya mungkin terlihat seperti ini:

GET /db/questions HTTP/1.1
Host: paged.collection.example
Accept: application/json;PagingSpec=1.0;page=1

The Acceptsundulan memungkinkan Anda untuk menentukan jenis diterima konten (JSON Anda kembali), ditambah parameter extensible untuk jenis yang (nomor halaman Anda). Mengasah catatan saya dari tulisan oEmbed saya (tidak dapat menautkannya di sini, saya akan mencantumkannya di profil saya), Anda bisa sangat eksplisit dan memberikan versi spesifikasi / relasi di sini jika Anda perlu mendefinisikan ulang apa arti pageparameter di masa depan.


1
+1 header tautan, tetapi saya juga merekomendasikan rels pertama, prev, next, last, serta prev-archive, next-archive, dan current RFC5005 yang umum.
Joseph Holsten

> Pada permintaan ke / db / pertanyaan, kembalikan 300 Pilihan Ganda dengan tajuk Tautan yang menentukan bagaimana menuju ke setiap halaman [..] Masalah dengan itu (dan dengan sebagian besar desain REST murni) adalah mematikan latensi. Tujuannya adalah untuk meminimalkan permintaan jaringan. Permintaan pertama itu harus memberikan hasil, bukan tautan ke lebih banyak permintaan yang pada akhirnya akan memberikan data yang kita butuhkan.
Stijn de Witt

4

Edit:

Setelah memikirkannya lebih dalam, saya cenderung setuju bahwa header Range tidak sesuai untuk penomoran halaman. Logikanya, header Range ditujukan untuk respon server, bukan aplikasi. Jika Anda menyajikan hasil 100 megabyte, tetapi server (atau klien) hanya dapat memproses 1 megabyte dalam satu waktu, untuk itulah header Range digunakan.

Saya juga berpendapat bahwa subset sumber daya adalah sumber dayanya sendiri (mirip dengan aljabar relasional.), Sehingga layak untuk ditampilkan dalam URL.

Jadi pada dasarnya, saya menarik kembali jawaban asli saya (di bawah) tentang menggunakan header.


Saya rasa Anda menjawab pertanyaan Anda sendiri, kurang lebih - kembalikan 200 atau 206 dengan rentang konten dan gunakan parameter kueri secara opsional. Saya akan mengendus agen pengguna dan jenis konten dan, bergantung pada mereka, memeriksa parameter kueri. Jika tidak, memerlukan header rentang.

Anda pada dasarnya memiliki tujuan yang bertentangan - biarkan orang menggunakan browser mereka untuk menjelajah (yang tidak memungkinkan header kustom dengan mudah), atau memaksa orang untuk menggunakan klien khusus yang dapat menyetel header (yang tidak memungkinkan mereka menjelajah).

Anda bisa memberi mereka klien khusus tergantung pada permintaan - jika itu terlihat seperti browser biasa, turunkan aplikasi ajax kecil yang merender halaman dan mengatur header yang diperlukan.

Tentu saja, ada juga perdebatan tentang apakah URL harus berisi semua status yang diperlukan untuk hal semacam ini. Menentukan rentang menggunakan tajuk dapat dianggap "tidak tenang" oleh beberapa orang.

Selain itu, alangkah baiknya jika server dapat merespons dengan header "Can-Specify: Header1, header2", dan browser web akan menampilkan UI sehingga pengguna dapat mengisi nilai, jika mereka mau.


Terima kasih atas tanggapannya. Saya telah memikirkan tentang topik tersebut, tetapi berharap mendapatkan opini kedua. Apakah memiliki pointer untuk argumen header?
Karl Guertin

Inilah satu-satunya yang telah saya tandai (lihat pembahasan di komentar): nyarisenough.org/blog/2008/05/versioning-rest-web-services Situs lain berputar di sekitar penggunaan Ruby .json, .xml, .apa pun dalam menentukan jenis konten permintaan. Beberapa contoh: * bahasa - memasukkannya ke dalam URL berarti mengirim tautan ke negara lain akan membuatnya dalam bahasa yang salah. * penomoran halaman - Menempatkannya di tajuk berarti Anda tidak dapat menautkan orang ke apa yang Anda lihat
Richard Levasseur

* jenis konten: kombinasi masalah bahasa dan penomoran halaman - jika ada di url, bagaimana jika klien tidak mendukung jenis konten tersebut (misalnya, ekstensi .ajax dan .html)? Sebaliknya, tanpa tipe konten tersebut di url, Anda tidak dapat memastikan representasi yang sama diberikan. "situs ajax baru! example.com/cool.ajax" vs "artikel keren di sini: example.com/article.ajax#id=123".
Richard Levasseur

2
IMO, apakah itu masuk ke dalam URL atau tidak tergantung pada apa itu. Aturan umum saya adalah, jika itu akan mengidentifikasi sumber daya konkret (baik itu sumber daya di negara bagian tertentu, pemilihan sumber daya, atau hasil diskrit), itu masuk di URL. Kueri penelusuran, penomoran halaman, dan transaksi tenang adalah contoh yang bagus untuk ini. Jika itu adalah sesuatu yang diperlukan untuk mengubah representasi abstrak menjadi representasi konkret, ia masuk ke header. info auth dan jenis konten adalah contoh yang bagus untuk ini.
Richard Levasseur

Saya menganggap string kueri di URL sebagai opsi untuk menanyakan sumber daya yang ditentukan.
wprl

3

Anda dapat mempertimbangkan untuk menggunakan model seperti Atom Feed Protocol karena model tersebut memiliki koleksi model HTTP yang waras dan cara memanipulasinya (di mana gila berarti WebDAV).

Ada Atom Publishing Protocol yang mendefinisikan model koleksi dan operasi REST plus Anda dapat menggunakan RFC 5005 - Feed Paging and Archiving ke halaman melalui koleksi besar.

Beralih dari Atom XML ke konten JSON seharusnya tidak mempengaruhi gagasan.


3

Saya rasa masalah sebenarnya di sini adalah tidak ada dalam spesifikasi yang memberi tahu kita cara melakukan pengalihan otomatis saat dihadapkan dengan 413 - Entitas yang Diminta Terlalu Besar.

Saya berjuang dengan masalah yang sama baru-baru ini dan saya mencari inspirasi di buku RESTful Web Services . Secara pribadi menurut saya 206 tidak sesuai karena persyaratan header. Pikiran saya juga membawa saya ke 300, tapi saya pikir itu lebih untuk tipe pantomim yang berbeda, jadi saya mencari apa yang dikatakan Richardson dan Ruby tentang subjek di Lampiran B, halaman 377. Mereka menyarankan bahwa server hanya memilih yang disukai representasi dan mengirimkannya kembali dengan 200, pada dasarnya mengabaikan gagasan bahwa itu harus 300.

Itu juga cocok dengan gagasan tentang tautan ke sumber daya berikutnya yang kita miliki dari atom. Solusi yang saya terapkan adalah menambahkan kunci "berikutnya" dan "sebelumnya" ke peta json yang saya kirim kembali dan selesai dengannya.

Kemudian saya mulai berpikir mungkin hal yang harus dilakukan adalah mengirim 307 - Pengalihan Sementara ke tautan yang akan menjadi seperti / db / pertanyaan / 1,25 - yang meninggalkan URI asli sebagai nama sumber daya kanonik, tetapi itu membuat Anda sumber daya bawahan yang diberi nama dengan tepat. Ini adalah perilaku yang ingin saya lihat dari 413, tetapi 307 tampaknya kompromi yang baik. Belum benar-benar mencoba kode ini. Apa yang lebih baik lagi adalah pengalihan untuk mengarahkan ke URL yang berisi ID sebenarnya dari pertanyaan terbaru yang diajukan. Misalnya jika setiap pertanyaan memiliki ID bilangan bulat, dan ada 100 pertanyaan dalam sistem dan Anda ingin menampilkan sepuluh pertanyaan terbaru, permintaan ke / db / pertanyaan harus 307 ke / db / pertanyaan / 100,91

Ini pertanyaan yang sangat bagus, terima kasih telah menanyakannya. Anda menegaskan kepada saya bahwa saya tidak gila karena telah menghabiskan berhari-hari memikirkannya.


303 akan lebih baik dalam hal ini daripada 307. 307 menyiratkan bahwa URL asli akan segera mulai merespons seperti yang diharapkan klien.
Nicholas Shanks

RFC 7231 merujuk kode status HTTP 413 sebagai Payload Too Large dan menghubungkan kode ini dengan ukuran permintaan dan bukan ukuran respons potensial.
beawolf

2

Salah satu masalah besar dengan header rentang adalah banyak proxy perusahaan yang memfilternya. Saya menyarankan untuk menggunakan parameter kueri sebagai gantinya.



1

Anda dapat mendeteksi Rangeheader, dan meniru Dojo jika ada, dan meniru Atom jika tidak ada. Menurut saya, ini dengan rapi membagi kasus penggunaan. Jika Anda merespons kueri REST dari aplikasi Anda, Anda mengharapkannya diformat dengan Rangeheader. Jika Anda merespons peramban biasa, maka jika Anda mengembalikan tautan paging, alat tersebut akan memberikan cara mudah untuk menjelajahi koleksi.


0

Menurut saya cara terbaik untuk melakukan ini adalah dengan menyertakan rentang sebagai parameter kueri. misalnya, GET / db / question /? date> mindate & date <maxdate . Setelah GET ke / db / pertanyaan / tanpa parameter kueri, kembalikan 303 dengan Lokasi: / db / pertanyaan /? Query-parameter-to-mengambil-the-default-page . Kemudian berikan URL yang berbeda dengan siapa pun yang menggunakan API Anda untuk mendapatkan statistik tentang koleksi (misalnya, parameter kueri apa yang akan digunakan jika dia menginginkan seluruh koleksi);


0

Meskipun mungkin untuk menggunakan header Range untuk tujuan ini, saya rasa bukan itu tujuannya. Tampaknya telah dirancang untuk menangani koneksi yang tidak stabil serta membatasi data (sehingga klien dapat meminta bagian dari permintaan jika ada sesuatu yang hilang atau ukurannya terlalu besar untuk diproses). Anda meretas pagination menjadi sesuatu yang mungkin digunakan untuk tujuan lain di lapisan komunikasi. Cara yang "tepat" untuk menangani penomoran halaman adalah dengan jenis yang Anda kembalikan. Daripada mengembalikan objek pertanyaan, Anda harus mengembalikan tipe baru.

Jadi jika pertanyaannya seperti ini:

<questions> <question index=1></question> <question index=2></question> ... </questions>

Jenis baru bisa jadi seperti ini:

<questionPage> <startIndex>50</startIndex> <returnedCount>10</returnedCount> <totalCount>1203</totalCount> <questions> <question index=50></question> <question index=51></question> .. </questions> <questionPage>

Tentu saja Anda mengontrol jenis media Anda, sehingga Anda dapat membuat "halaman" Anda dalam format yang sesuai dengan kebutuhan Anda. Jika Anda membuatnya adalah sesuatu yang umum, Anda dapat memiliki parser tunggal pada klien untuk menangani paging yang sama untuk semua jenis. Saya pikir itu lebih dalam semangat spesifikasi HTTP, daripada memalsukan parameter Range untuk sesuatu yang lain.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.