Làm cách nào để giải quyết các giới hạn độ dài chuỗi truy vấn HTTP GET mà vẫn muốn RESTful?


84

Như đã nêu trong http://www.boutell.com/newfaq/misc/urllength.html , chuỗi truy vấn HTTP có độ dài giới hạn. Nó có thể bị giới hạn bởi máy khách (Firefox, IE, ...), máy chủ (Apache, IIS, ...) hoặc thiết bị mạng (tường lửa ứng dụng, ...).

Hôm nay tôi phải đối mặt với vấn đề này với một biểu mẫu tìm kiếm. Chúng tôi đã phát triển một biểu mẫu tìm kiếm với rất nhiều trường và biểu mẫu này được gửi đến máy chủ dưới dạng yêu cầu GET, vì vậy tôi có thể đánh dấu trang kết quả.

Chúng tôi có rất nhiều trường nên chuỗi truy vấn của chúng tôi dài 1100 byte và chúng tôi có tường lửa loại bỏ các yêu cầu HTTP GET với hơn 1024 byte. Quản trị viên hệ thống của chúng tôi khuyến nghị chúng tôi sử dụng POST để thay thế, vì vậy sẽ không có giới hạn.

Chắc chắn, POST sẽ hoạt động, nhưng tôi thực sự cảm thấy tìm kiếm là một NHẬN chứ không phải một ĐĂNG. Vì vậy, tôi nghĩ rằng tôi sẽ xem xét các tên trường của chúng tôi để đảm bảo chuỗi truy vấn không quá dài và nếu không thể, tôi sẽ thực dụng và sử dụng POST.

Nhưng có một lỗ hổng nào trong việc thiết kế các dịch vụ RESTful không? Nếu chúng tôi có độ dài giới hạn trong yêu cầu GET, tôi có thể làm thế nào để gửi các đối tượng lớn đến một dịch vụ web RESTful? Ví dụ, nếu tôi có một chương trình mà làm cho tính toán dựa trên một tập tin, và tôi muốn cung cấp một webservice RESTful như thế này: http://compute.com?content=<base64 file>. Điều này sẽ không hoạt động vì chuỗi truy vấn có độ dài không giới hạn.

Tôi hơi khó hiểu ...


2
Nghỉ ngơi có nghĩa là gì trong bối cảnh của bạn? Hoặc diễn giải: tại sao GET là yên tĩnh và POST thì không? Vì GET có thể được xây dựng bằng cách sử dụng nối chuỗi đơn giản? Giới hạn độ dài truy vấn là để tránh phân bổ bộ nhớ động trong các ứng dụng nhằm hoạt động nhanh.
khachik

5
Khi tôi muốn tìm kiếm, tôi không muốn tạo, xóa hay cập nhật gì đó, tôi chỉ muốn truy xuất dữ liệu, vì vậy tôi không nên sử dụng POST, DELETE hoặc PUT và tôi nên sử dụng GET. Đây là cách tôi hiểu REST của nhưng tôi có thể bị nhầm lẫn về nó
cbliard

GET không thích hợp để tìm kiếm, vì kết quả tìm kiếm có thể thay đổi theo thời gian. Cơ sở hạ tầng web thường cho phép lưu vào bộ nhớ đệm các yêu cầu GET. Nếu bạn sử dụng GET, bạn có nguy cơ nhận được kết quả cũ cho các tìm kiếm. POST là cách, như được đề xuất dưới đây.
Occulus

15
Tất cả mọi thứ thay đổi giờ làm thêm ( en.wikipedia.org/wiki/Impermanence ), đó là bản chất của vũ trụ ... Nhưng GET nên được sử dụng để tìm kiếm vì "tìm kiếm hành động" không làm thay đổi kết quả
Luxspes

Câu trả lời:


51

Dựa trên mô tả của bạn, IMHO, bạn nên sử dụng ĐĂNG. POST là để đưa dữ liệu lên máy chủ và trong một số trường hợp, có được câu trả lời. Trong trường hợp của bạn, bạn thực hiện một tìm kiếm (gửi một truy vấn đến máy chủ) và nhận được kết quả của tìm kiếm đó (lấy kết quả truy vấn).

Định nghĩa của GET nói rằng nó phải được sử dụng để lấy một tài nguyên đã tồn tại. Theo định nghĩa, POST là tạo một tài nguyên mới. Đây chính xác là những gì bạn đang làm: tạo một tài nguyên trên máy chủ và truy xuất nó! Ngay cả khi bạn không lưu trữ kết quả tìm kiếm, bạn đã tạo một đối tượng trên máy chủ và truy xuất nó. Như PeterMmm đã nói trước, bạn có thể làm điều này với POST (tạo và lưu trữ kết quả truy vấn) và sau đó sử dụng GET để truy xuất lại truy vấn, nhưng thực tế hơn chỉ thực hiện POST và truy xuất kết quả.

Hi vọng điêu nay co ich! :)


2
Bạn nói đúng, tôi có thể xem nó như một BÀI ĐĂNG vì tìm kiếm là một tài nguyên mới được tính toán dễ bay hơi. Nhưng tôi vẫn gặp vấn đề khi thấy ranh giới giữa ĐĂNG và NHẬN. Nếu tôi muốn tìm kiếm tất cả sách khoa học viễn tưởng trong thư viện, tôi sẽ nhận được một bộ sưu tập các tài nguyên hiện có, vì vậy tôi muốn sử dụng GET, nhưng bạn đề xuất xem nó như một BÀI ĐĂNG vì bản thân tìm kiếm là một tài nguyên mới. Vì vậy, chuỗi truy vấn trong GET chỉ nên được sử dụng để thay đổi biểu diễn dữ liệu chứ không phải để lọc dữ liệu. Tôi nói đúng chứ?
cbliard

8
POST không nên được sử dụng để tìm kiếm, GET là những gì nên được sử dụng, bằng cách này bạn có thể chia sẻ, và bộ nhớ cache, kết quả URL và các kết quả, và bạn tận dụng tốt hơn các kiến trúc RESTful của internet
Luxspes

37
Câu trả lời này nghe giống như đang cố gắng chơi với các từ. Theo logic đó, chúng tôi có thể thực hiện mọi thứ dưới dạng yêu cầu ĐĂNG mà vẫn có thể RESTful.
supertonsky vào

9
Câu trả lời này có vẻ như một số luật sư nói chuyện với tôi :-) Câu hỏi thực sự là "Tôi có một trường hợp GET, được rồi. Nhưng chuỗi truy vấn của tôi vượt quá độ dài cho phép. Làm thế nào để xử lý". Từ chối câu trả lời này.
G. Stoynev

2
Nếu logic đó tuân theo, thì mọi yêu cầu đang tạo ra một tài nguyên và truy xuất nó.
Alex

66

Đặc tả HTTP thực sự khuyên bạn nên sử dụng POST khi gửi dữ liệu đến một tài nguyên để tính toán.

Tìm kiếm của bạn trông giống như một phép tính, không phải là một tài nguyên. Điều bạn có thể làm nếu vẫn muốn kết quả tìm kiếm của mình là một tài nguyên là tạo một mã thông báo để xác định kết quả tìm kiếm cụ thể đó và chuyển hướng tác nhân người dùng đến tài nguyên đó.

Sau đó, bạn có thể xóa mã kết quả tìm kiếm sau một khoảng thời gian.

Thí dụ

POST /search
query=something&category=c1&category=c2&...

201 Created
Location: /search/01543164876

sau đó

GET /search/01543164876

200 Ok
... your results here...

Bằng cách này, trình duyệt và proxy vẫn có thể lưu kết quả tìm kiếm vào bộ nhớ cache nhưng bạn đang gửi tham số truy vấn của mình bằng POST.

BIÊN TẬP

Để làm rõ, 01543164876ở đây đại diện cho một ID duy nhất cho tài nguyên đại diện cho tìm kiếm của bạn. 2 yêu cầu đó về cơ bản có nghĩa là: tạo một đối tượng tìm kiếm mới với các tiêu chí này, sau đó truy xuất các kết quả được liên kết với đối tượng tìm kiếm đã tạo.

ID này có thể là một ID duy nhất được tạo cho mỗi yêu cầu mới. Điều này có nghĩa là máy chủ của bạn sẽ bị rò rỉ các đối tượng "tìm kiếm" và bạn sẽ phải làm sạch chúng thường xuyên bằng chiến lược bộ nhớ đệm.

Hoặc nó có thể là một hàm băm của tất cả các tiêu chí tìm kiếm thực sự đại diện cho tìm kiếm mà người dùng yêu cầu. Điều này cho phép bạn sử dụng lại các ID vì việc tạo lại một tìm kiếm sẽ trả về một ID hiện có có thể (hoặc không) đã được lưu trong bộ nhớ cache.


Điều này giải quyết yêu cầu OP về đánh dấu trang truy vấn như thế nào?
hoàng

2
@Rhubarb nó giải quyết vấn đề đó một cách rõ ràng bằng cách tạo một tài nguyên cho một tìm kiếm nhất định.
maulik13

3
Điều này sẽ làm chậm kết quả. Thực hiện một bài đăng và sau đó thực hiện một GET. nó sẽ thêm ít nhất 300ms nữa để lấy tìm kiếm.
jaxxbo

Liên kết đến nguồn đã chết
Emobe

Tôi bối rối, máy chủ làm gì giữa POST và GET? nó có cache dữ liệu tìm kiếm trên máy chủ và chỉ đợi yêu cầu GET đến không? Nó sẽ phải sử dụng một số id duy nhất để làm điều đó, vì vậy bạn có thể truy xuất bộ nhớ cache. Câu trả lời của bạn rất hay, nhưng chắc chắn là không đầy đủ. Và việc sử dụng bộ nhớ đệm sẽ làm cho mọi thứ ít trạng thái hơn.
Alexander Mills,

5

REST là một cách để thực hiện mọi thứ, không phải là một giao thức. Ngay cả khi bạn không thích ĐĂNG khi nó thực sự là GET, nó vẫn hoạt động.

Nếu bạn sẽ / phải ở với định nghĩa "tiêu chuẩn" của GET, POST, v.v. có thể xem xét ĐĂNG một truy vấn, truy vấn đó sẽ được lưu trữ trên máy chủ với một id truy vấn và yêu cầu truy vấn sau với GET theo id.


4

Về ví dụ của bạn:, http://compute.com?content={base64file}tôi sẽ sử dụng POST vì bạn đang tải lên "một cái gì đó" được tính toán. Đối với tôi, "cái gì đó" giống như một tài nguyên hơn như một tham số đơn giản.

Ngược lại với điều này trong tìm kiếm thông thường, tôi sẽ bắt đầu gắn bó với GET và các tham số. Bạn giúp các ứng dụng khách có thể kiểm tra và chơi với api của bạn dễ dàng hơn rất nhiều. Làm cho quyền truy cập chỉ đọc (trong hầu hết các trường hợp là phần lớn lưu lượng truy cập) càng đơn giản càng tốt!

Nhưng vấn đề nan giải của các chuỗi truy vấn lớn là một hạn chế hợp lệ của GET. Ở đây tôi sẽ thực dụng, miễn là bạn không đạt đến giới hạn này, hãy sử dụng GET và url-params. Điều này sẽ hoạt động trong 98% các trường hợp tìm kiếm. Chỉ hành động nếu bạn đạt đến giới hạn này và sau đó cũng giới thiệu POST với tải trọng (với kiểu mime Content-Type: application/x-www-form-urlencoded).

Bạn có thêm ví dụ trong thế giới thực không?


Việc tính toán là một ví dụ thực tế. Về phần tìm kiếm, chúng tôi muốn có thể tìm kiếm các giao dịch trên nhiều điểm bán, vì vậy chúng tôi mở một cửa sổ trình duyệt mới để chọn các điểm bán. Và khi chúng tôi xác thực, chúng tôi sẽ sửa đổi một tham số ẩn trong biểu mẫu tìm kiếm để đặt các điểm bán hàng đã chọn. Nếu thực sự có nhiều trong số chúng, thì yêu cầu tìm kiếm kết quả sẽ có một chuỗi truy vấn rất dài.
cbliard

4

Sự nhầm lẫn xung quanh GET là một hạn chế của trình duyệt. Nếu bạn đang tạo giao diện RESTful cho ứng dụng A2A hoặc P2P thì không có giới hạn về thời lượng GET của bạn.

Bây giờ, nếu bạn tình cờ muốn sử dụng trình duyệt để xem giao diện RESTful của mình (hay còn gọi là trong quá trình phát triển / gỡ lỗi) thì bạn sẽ gặp phải giới hạn này, nhưng vẫn có các công cụ để giải quyết vấn đề này.


6
"GET là một giới hạn của trình duyệt" - nó cũng là một giới hạn của máy chủ. Bạn sẽ thấy tất cả các máy chủ web thực thi giới hạn và nếu bạn có CDN, chúng cũng có thể thực thi một giới hạn. Sử dụng các công cụ khác để thực hiện yêu cầu sẽ không vượt qua giới hạn của máy chủ.
Courtney Miles

0

Đây là một điều dễ dàng. Sử dụng POST. HTTP không áp đặt giới hạn về độ dài URL cho GET nhưng các máy chủ thì có. Hãy thực dụng và giải quyết vấn đề đó bằng BÀI ĐĂNG.

Bạn cũng có thể sử dụng phần thân GET (được phép) nhưng đó là một vấn đề kép ở chỗ nó không được sử dụng đúng cách và có thể sẽ gặp sự cố máy chủ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.