Mã trạng thái REST HTTP để xác thực không thành công hoặc trùng lặp không hợp lệ


826

Tôi đang xây dựng một ứng dụng với API dựa trên REST và đã đến lúc tôi chỉ định mã trạng thái cho mỗi yêu cầu.

Tôi nên gửi mã trạng thái nào cho các yêu cầu không xác thực hoặc yêu cầu đang cố gắng thêm một bản sao trong cơ sở dữ liệu của tôi?

Tôi đã xem qua http://www.w3.org/Prot Protocol / rfc2616 / rfc2616-sec10.html nhưng không ai trong số họ có vẻ đúng.

Có một thực tế phổ biến khi gửi mã trạng thái?



14
Mở httpstatus.es , Nhấp chuột phải >> Tab Pin: P
Salman von Abbas

Câu trả lời:


780

Đối với lỗi xác thực đầu vào: 400 Yêu cầu xấu + mô tả tùy chọn của bạn. Điều này được đề xuất trong cuốn sách " RESTful Web Services ". Để gửi gấp đôi: 409 Xung đột


Cập nhật tháng 6 năm 2014

Thông số kỹ thuật có liên quan được sử dụng là RFC2616 , cho phép sử dụng 400 (Yêu cầu xấu) khá hẹp như

Máy chủ không thể hiểu được yêu cầu do cú pháp không đúng

Vì vậy, nó có thể đã được lập luận rằng nó không phù hợp cho các lỗi ngữ nghĩa. Nhưng không còn nữa; kể từ tháng 6 năm 2014, RFC 7231 tiêu chuẩn có liên quan , thay thế cho RFC2616 trước đó, cho phép sử dụng rộng rãi hơn 400 (Yêu cầu xấu)

máy chủ không thể hoặc sẽ không xử lý yêu cầu do lỗi được coi là lỗi máy khách


3
Có, phần thân yêu cầu là một phần của cú pháp.
deamon

62
Yêu cầu xấu chắc chắn là phản ứng phổ biến nhất cho loại vấn đề này. Sự thay thế duy nhất khác là 422 Thực thể không thể xử lý. Nó thực sự đến từ WebDav nhưng nó hoàn toàn hợp lệ để sử dụng lại bất kỳ mã trạng thái nào đã được đăng ký với IANA.
Darrel Miller

19
Vậy làm thế nào để bạn phân biệt giữa dữ liệu không đúng định dạng mà máy chủ thậm chí không thể phân tích cú pháp và lỗi xác thực? Một khách hàng sẽ xử lý hai phản ứng này hoàn toàn khác nhau. Để xác thực, họ có thể sẽ hiển thị các lỗi cho người dùng. Đối với "dữ liệu không đúng định dạng" thực sự, họ sẽ ghi lại lỗi để lỗi trong phương thức tạo yêu cầu có thể được sửa.
Josh Noe

18
Tôi không đồng ý với cách giải thích của bạn về RFC7231, mặc dù nó nêu rõ something perceived to be a client error, tất cả các ví dụ được nêu trong đoạn này là vi phạm giao thức HTTP, không phải lỗi logic: cú pháp, khung, định tuyến. Vì vậy, tôi cho rằng thông số HTTP không cho phép 400 xác nhận thất bại ở cấp ứng dụng.
Dima Tisnek

2
Tại sao không sử dụng một thực thể 422 - Không thể xử lý? Có vẻ hợp lý hơn với tôi
java_geek

278
  • Xác thực thất bại: 403 Bị cấm ("Máy chủ hiểu yêu cầu, nhưng từ chối thực hiện"). Trái với ý kiến ​​phổ biến, RFC2616 không nói "403 chỉ nhằm mục đích xác thực thất bại", nhưng "403: Tôi biết bạn muốn gì, nhưng tôi sẽ không làm điều đó". Điều kiện đó có thể hoặc không thể do xác thực.
  • Cố gắng thêm một bản sao: 409 Xung đột ("Không thể hoàn thành yêu cầu do mâu thuẫn với trạng thái hiện tại của tài nguyên.")

Bạn chắc chắn nên đưa ra lời giải thích chi tiết hơn trong các tiêu đề và / hoặc phần thân phản hồi (ví dụ: với tiêu đề tùy chỉnh - X-Status-Reason: Validation failed).


17
@deamon: Đó không phải là đặc điểm kỹ thuật, đó là Wikipedia, tức là ý kiến ​​của ai đó về "ý nghĩa của mã trạng thái HTTP"; lưu ý rằng trang Essentialy nói "đây là ý nghĩa của Apache với 403, đây là ý nghĩa của IIS với 403" và không nơi nào tham chiếu RFC chính thức. Bạn dường như đang lặp lại "403 có nghĩa là bất cứ điều gì Apache nói". KHÔNG PHẢI. RFC thực tế (là tài liệu có liên quan, không phải triển khai của Apache, không phải triển khai IIS, không phải của ai khác) ở đây: w3.org/Prot Protocol / rfc2616 / rfc2616
Piskvor rời khỏi tòa nhà vào

57
"10.4.4 403 Bị cấm Máy chủ hiểu yêu cầu, nhưng từ chối thực hiện. Ủy quyền sẽ không giúp ích và yêu cầu KHÔNG NÊN lặp lại. Nếu phương thức yêu cầu không phải là CHÍNH và máy chủ muốn công khai tại sao yêu cầu không đã được thực hiện, nó NÊN mô tả lý do từ chối trong thực thể. Nếu máy chủ không muốn cung cấp thông tin này cho khách hàng, có thể sử dụng mã trạng thái 404 (Không tìm thấy). " Tôi thấy không có sự nhấn mạnh nào ở đó ("NÊN / KHÔNG NÊN" là các từ khóa RFC 2119, không nhấn mạnh); đó là ý tưởng của bạn "cấm" nghĩa là gì, không phải của RFC.
Piskvor rời khỏi tòa nhà vào

10
Tôi thích câu trả lời này, nhưng vẫn thấy một vấn đề nhỏ. Theo thông số kỹ thuật , khi trả lại 403 , "yêu cầu KHÔNG NÊN lặp lại". Tuy nhiên, trả lại 409 "chỉ được phép trong các tình huống mà người dùng dự kiến ​​có thể giải quyết xung đột và gửi lại yêu cầu". Trong trường hợp trùng lặp, tôi nghĩ 403 sau đó phù hợp hơn, vì bạn không thể thực sự giải quyết xung đột (ngoại trừ bằng cách xóa phiên bản trước của tài nguyên).
pablobm

2
Đối với thông báo lỗi, bạn nên sửa đổi cụm từ lý do, vì vậy gửi tiêu đề HTTP/1.0 403 Form validation errorslà cách tốt nhất để đi.
aleemb

6
IMO, 422 "Thực thể không thể xử lý" có ý nghĩa hơn nhiều. Lý do của tôi là không phải máy chủ từ chối thực hiện yêu cầu, mà là máy chủ không thể thực hiện yêu cầu.
tybro0103

225

Tôi đề nghị mã trạng thái 422, "Thực thể không thể xử lý" .

11.2. Thực thể không thể xử lý 422

Mã trạng thái 422 (Thực thể không thể xử lý) có nghĩa là máy chủ hiểu loại nội dung của thực thể yêu cầu (do đó mã trạng thái 415 (Loại phương tiện không được hỗ trợ) là không phù hợp) và cú pháp của thực thể yêu cầu là chính xác (do đó là 400 (Yêu cầu sai ) mã trạng thái không phù hợp) nhưng không thể xử lý các hướng dẫn có trong đó. Ví dụ, điều kiện lỗi này có thể xảy ra nếu một thân yêu cầu XML chứa các hướng dẫn XML được định dạng đúng (nghĩa là đúng về mặt cú pháp), nhưng sai về mặt ngữ nghĩa, về mặt ngữ nghĩa.


11
Tất nhiên đó là mã trạng thái HTTP, xem iana.org/assignments/http-status-codes . Có nhiều mã trạng thái hơn mã được xác định trong RFC 2616.
Julian Reschke

7
WebDAV là một phần mở rộng HTTP . "Tiện ích mở rộng HTTP cho tác giả và phiên bản phân tán trên web (WebDAV)" Vì vậy, mã trạng thái 422 không phải là mã trạng thái http, mà là mã trạng thái của một lần loại trừ http.
deamon

16
deamon, điều đó không có ý nghĩa. HTTP định nghĩa cách xác định mã mới và đó là những gì WebDAV đang làm. Có một lý do đăng ký mã trạng thái.
Julian Reschke

14
Mô tả FYI - RFC của 422: 11.2. Thực thể không thể xử lý 422 Mã trạng thái 422 (Thực thể không thể xử lý) có nghĩa là máy chủ hiểu loại nội dung của thực thể yêu cầu (do đó mã trạng thái 415 (Loại phương tiện không được hỗ trợ) là không phù hợp) và cú pháp của thực thể yêu cầu là chính xác (do đó 400 (Yêu cầu xấu) mã trạng thái không phù hợp) nhưng không thể xử lý các hướng dẫn có trong đó. Ví dụ, điều kiện lỗi này có thể xảy ra nếu một thân yêu cầu XML chứa các hướng dẫn XML được định dạng đúng (nghĩa là đúng về mặt cú pháp), nhưng sai về mặt ngữ nghĩa, về mặt ngữ nghĩa.
Steve Kallestad

6
Và chủ đề không 'hết hạn'. Họ cần được giữ sống hoặc kết quả tìm kiếm hàng đầu của google bắt đầu trở nên không chính xác.
James Billingham

81

200.300, 400, 500 đều rất chung chung. Nếu bạn muốn chung chung, 400 là OK.

422 được sử dụng bởi số lượng API ngày càng tăng và thậm chí còn được Rails sử dụng ngoài hộp.

Bất kể mã trạng thái nào bạn chọn cho API của mình, ai đó sẽ không đồng ý. Nhưng tôi thích 422 vì tôi nghĩ '400 + trạng thái văn bản' là quá chung chung. Ngoài ra, bạn không tận dụng trình phân tích cú pháp sẵn sàng JSON; ngược lại, một 422 với phản hồi JSON là rất rõ ràng và rất nhiều thông tin lỗi có thể được chuyển tải.

Nói về phản hồi JSON, tôi có xu hướng chuẩn hóa phản hồi lỗi Rails cho trường hợp này, đó là:

{
    "errors" :
    { 
        "arg1" : ["error msg 1", "error msg 2", ...]
        "arg2" : ["error msg 1", "error msg 2", ...]
    }
}

Định dạng này là hoàn hảo để xác thực mẫu, mà tôi cho là trường hợp phức tạp nhất để hỗ trợ về 'mức độ giàu báo cáo lỗi'. Nếu cấu trúc lỗi của bạn là thế này, nó có thể sẽ xử lý tất cả các nhu cầu báo cáo lỗi của bạn.


2
Điều gì về lỗi phát sinh từ các tương tác giữa các đối số. Đó là, arg1hợp lệ và arg2hợp lệ, nhưng sự kết hợp của cả hai, với các giá trị cụ thể được gửi, không hợp lệ.
Giô-na

1
Tôi sẽ không nghĩ về nó; chỉ cần chọn một trong đó xuất hiện để sở hữu các mối quan hệ.
sethcall

hoặc thậm chí chỉ lỗi trên cả hai đối số. Là một người dùng, tôi nghĩ rằng tôi muốn thấy lỗi trên từng trường xung đột, tôi nghĩ vậy.
rình mò

Đẹp!. rõ ràng là tốt hơn so với ngầm
bhathiya-perera

46

200

Ugh ... (309, 400, 403, 409, 415, 422) ... rất nhiều câu trả lời cố gắng đoán, tranh luận và chuẩn hóa đâu là mã trả lại tốt nhất cho yêu cầu HTTP thành công nhưng cuộc gọi REST thất bại .

Việc trộn mã trạng thái HTTP và mã trạng thái REST là sai .

Tuy nhiên, tôi đã thấy nhiều triển khai trộn lẫn chúng và nhiều nhà phát triển có thể không đồng ý với tôi.

Mã trả về HTTP có liên quan đến HTTP Requestchính nó. Một cuộc gọi REST được thực hiện bằng cách sử dụng yêu cầu Giao thức truyền siêu văn bản và nó hoạt động ở mức thấp hơn so với chính phương thức REST được gọi. REST là một khái niệm / cách tiếp cận và đầu ra của nó là kết quả kinh doanh / logic , trong khi mã kết quả HTTP là một phương tiện giao thông .

Ví dụ: trả về "404 Không tìm thấy" khi bạn gọi / người dùng / bị nhầm lẫn, bởi vì điều đó có thể có nghĩa là:

  • URI sai (HTTP)
  • Không tìm thấy người dùng (REST)

"403 Bị cấm / Truy cập bị từ chối" có thể có nghĩa là:

  • Cần có sự cho phép đặc biệt Trình duyệt có thể xử lý nó bằng cách hỏi người dùng / mật khẩu. (HTTP)
  • Quyền truy cập sai được cấu hình trên máy chủ. (HTTP)
  • Bạn cần được xác thực (REST)

Và danh sách có thể tiếp tục với '500 Lỗi máy chủ "(lỗi ném HTTP / Nginx HTTP hoặc lỗi ràng buộc kinh doanh trong REST) ​​hoặc các lỗi HTTP khác, v.v ...

Từ mã, thật khó để hiểu lý do thất bại là gì, lỗi HTTP (vận chuyển) hay lỗi REST (logic).

Nếu yêu cầu HTTP được thực hiện thành công, nó sẽ luôn trả về 200 mã, bất kể (các) bản ghi có được tìm thấy hay không. Bởi vì tài nguyên URI được tìm thấy và được xử lý bởi máy chủ HTTP. Vâng, nó có thể trả về một bộ trống. Có thể nhận được một trang web trống với kết quả 200 như HTTP không?

Thay vì điều này, bạn có thể trả về 200 mã HTTP với một số tùy chọn:

  • Đối tượng "lỗi" trong kết quả JSON nếu có lỗi xảy ra
  • Mảng / đối tượng JSON trống nếu không tìm thấy bản ghi
  • Cờ kết quả / thành công bool kết hợp với các tùy chọn trước đó để xử lý tốt hơn.

Ngoài ra, một số nhà cung cấp internet có thể chặn yêu cầu của bạn và trả lại cho bạn mã HTTP 404. Điều này không có nghĩa là dữ liệu của bạn không được tìm thấy, nhưng có gì đó không đúng ở cấp độ vận chuyển.

Từ Wiki :

Vào tháng 7 năm 2004, nhà cung cấp dịch vụ viễn thông BT Group của Anh đã triển khai hệ thống chặn nội dung Cleanfeed, trả về lỗi 404 cho bất kỳ yêu cầu nào về nội dung được xác định là có thể bất hợp pháp bởi Internet Watch Foundation. Các ISP khác trả về lỗi "cấm" HTTP 403 trong cùng trường hợp. Việc sử dụng các lỗi 404 giả như một phương tiện để che giấu kiểm duyệt cũng đã được báo cáo ở Thái Lan và Tunisia. Ở Tunisia, nơi kiểm duyệt nghiêm trọng trước cuộc cách mạng năm 2011, mọi người đã nhận thức được bản chất của lỗi 404 giả và tạo ra một nhân vật tưởng tượng có tên "Ammar 404" đại diện cho "người kiểm duyệt vô hình".

Tại sao không chỉ đơn giản là trả lời với một cái gì đó như thế này?

{
  "result": false,
  "error": {"code": 102, "message": "Validation failed: Wrong NAME."}
}

Google luôn trả lại 200 dưới dạng mã trạng thái trong API mã hóa địa lý của họ, ngay cả khi yêu cầu không thành công về mặt logic: https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes

Facebook luôn trả lại 200 cho các yêu cầu HTTP thành công, ngay cả khi yêu cầu REST không thành công: https://developers.facebook.com/docs/graph-api/USE-graph-api/error-handling

Thật đơn giản, mã trạng thái HTTP dành cho các yêu cầu HTTP. API REST là của bạn, xác định mã trạng thái của bạn.


3
Trên thực tế, việc sử dụng mã trạng thái HTTP cho REST thậm chí còn khó hiểu hơn: 1) bạn thấy 4xx trong hộp công cụ của nhà phát triển và bạn không thể nói bằng cách chỉ nhìn vào nó dù máy chủ trả về một số giá trị hợp lý hay không thể xử lý yêu cầu của bạn và sau đó 2) tất cả các trình xử lý lỗi / ngoại lệ / bắt của bạn nên kiểm tra xem máy chủ nào trả về dưới dạng phản hồi (chủ yếu là vì bạn không phải làm điều đó trên mỗi cuộc gọi dịch vụ) và nhiều lần 3) bạn sẽ nhận được cùng một tải trọng ( loại) trên cả đường dẫn thành công và lỗi dẫn đến mã phức tạp / trùng lặp ... Thực sự rất khó hiểu.
szczepanpp

9
Câu trả lời này nhầm lẫn giữa ngữ nghĩa gốc của giao thức HTTP so với cách REST qua HTTP như một kiểu kiến ​​trúc nhằm mục đích HTTP để triển khai API dịch vụ web. Là một phong cách kiến ​​trúc, REST không phải là một tiêu chuẩn để được tuân thủ nghiêm ngặt, đó là một cách tiếp cận được đề xuất. Sử dụng phản hồi 200 cho lỗi xác thực không phải là đúng hay sai, tuy nhiên, thật khó hiểu khi khách hàng của bạn trả lời rằng yêu cầu đã thành công, nhưng thực sự đã thất bại do lỗi xác thực, một chi tiết quan trọng bị che khuất trong cơ thể của phản hồi, ngữ nghĩa mà khách hàng phải phân tích để hiểu.
Kevin Hooke

5
@Marcodor nếu cuộc gọi API của bạn thất bại nhưng bạn trả lại 200 cho thấy thành công, đây là một ý tưởng tốt như thế nào? nó không rõ ràng và gây nhầm lẫn cho người tiêu dùng API của bạn.
Kevin Hooke

3
Chính xác vì nhiều lý do, không chỉ phân tách lỗi HTTP và REST. Xác thực REST thường đòi hỏi nhiều sắc thái. Ví dụ: hồ sơ được chấp nhận nhưng được gắn cờ là trùng lặp so với bị từ chối vì vi phạm chỉ mục duy nhất. Bạn cũng muốn một mô hình trở lại nhất quán. BadRequest()Phương thức .NET có mô hình trả về riêng của nó sẽ khác với mô hình trả về thông thường của bạn. Đó là một cơn ác mộng để phân tích. @KevinHooke, trả lại HTTP 200 cho lỗi xác thực REST giống như nói: "Tôi đã nhận được tin nhắn của bạn, câu trả lời là không, và đây là lý do." Trả lại HTTP 400, "Tôi không biết bạn đang nói về cái gì."
Neil Laslett

5
đối số "bởi vì Google làm điều đó, nó phải đúng" là điều điên rồ đối với tôi..có thể chấp nhận điều gì đó mà google đã triển khai cho trẻ em. Trả lại HTTP 200 cho một cuộc gọi nghỉ ngơi không thành công gây nhầm lẫn cho người gọi API, nó phải là 4xx và người ta có thể bao gồm một JSON / XML đẹp trong cơ thể ... để cùng nhau ngăn chặn sự điên rồ.
Jeryl Cook

43

Một bản sao trong cơ sở dữ liệu phải là một 409 CONFLICT .

Tôi khuyên bạn nên sử dụng 422 UNPROCESSABLE ENTITY cho các lỗi xác nhận.

Tôi giải thích dài hơn về mã 4xx ở đây .


6

Mã trạng thái 304 Không được sửa đổi cũng sẽ tạo ra phản hồi chấp nhận được đối với yêu cầu trùng lặp. Điều này tương tự như xử lý một tiêu đề If-None-Matchsử dụng thẻ thực thể.

Theo tôi, câu trả lời của @ Piskvor là sự lựa chọn rõ ràng hơn cho những gì tôi nhận thấy là mục đích của câu hỏi ban đầu, nhưng tôi có một cách thay thế cũng phù hợp.

Nếu bạn muốn coi một yêu cầu trùng lặp là một cảnh báo hoặc thông báo chứ không phải là một lỗi, mã trạng thái phản hồi của 304Không được sửa đổi vàContent-Location tiêu đề xác định tài nguyên hiện có sẽ có giá trị. Khi mục đích chỉ đơn thuần là để đảm bảo rằng tài nguyên tồn tại, một yêu cầu trùng lặp sẽ không phải là lỗi mà là xác nhận. Yêu cầu không sai, nhưng đơn giản là dư thừa và khách hàng có thể tham khảo tài nguyên hiện có.

Nói cách khác, yêu cầu là tốt, nhưng vì tài nguyên đã tồn tại, nên máy chủ không cần thực hiện bất kỳ xử lý nào nữa.


6
Theo hiểu biết của tôi, 304 được dành cho các hoạt động GET để hỗ trợ bộ nhớ đệm.
Trang web thẩm mỹ

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.