Tôi có nên sử dụng mã trạng thái HTTP để mô tả các sự kiện ở cấp ứng dụng


54

Một số máy chủ mà tôi đã xử lý sẽ trả về HTTP 200 cho các yêu cầu mà khách hàng phải xem xét là thất bại, với nội dung như 'thành công: sai' trong cơ thể.

Đây dường như không phải là một triển khai mã HTTP thích hợp, đặc biệt trong các trường hợp xác thực không thành công. Tôi đã đọc các mã lỗi HTTP khá ngắn gọn được tóm tắt là, '4xx' chỉ ra rằng yêu cầu không nên được thực hiện lại cho đến khi thay đổi, trong khi '5xx' chỉ ra rằng yêu cầu có thể hoặc không thể hợp lệ và có thể được thử lại, nhưng không thành công. Trong trường hợp này 200: đăng nhập thất bại hoặc 200: không thể tìm thấy tệp đó hoặc 200: thiếu tham số x, chắc chắn có vẻ sai.

Mặt khác, tôi có thể thấy đối số được đưa ra rằng '4xx' chỉ nên chỉ ra vấn đề cấu trúc với yêu cầu. Vì vậy, điều đó là đúng khi trả lại 200: người dùng / mật khẩu xấu thay vì trái phép 401 vì khách hàng được phép thực hiện yêu cầu, nhưng điều đó xảy ra là không chính xác. Đối số này có thể được tóm tắt là, nếu máy chủ có thể xử lý yêu cầu và đưa ra quyết định, mã phản hồi phải là 200 và tùy thuộc vào máy khách để kiểm tra thông tin thêm.

Về cơ bản, đây dường như là một vấn đề ưu tiên. Nhưng điều đó là không thỏa mãn, vì vậy nếu bất cứ ai có lý do tại sao một trong những mô hình này là chính xác hơn, tôi muốn biết.


9
success: falsengụ ý rằng yêu cầu thất bại và bạn biết điều đó. Đó phải là 500. Một cái gì đó giống như tên người dùng / mật khẩu xấu của bạn sẽ là một số 401. Đây không phải là điều mơ hồ.
Pete


4
Đây là một trong những câu hỏi có thể gây ra các cuộc chiến tôn giáo mà tôi nghĩ. Đối với API RESTful, câu trả lời rất rõ ràng, nhưng có nhiều loại API khác trong đó HTTP được coi như một lớp vận chuyển và trong những trường hợp đó, các lỗi ứng dụng không nên chảy vào lớp đó.
Gort Robot

5
Khi tôi thực sự không chắc chắn trạng thái http nào để trả về, nó luôn luôn hấp dẫn với 418 "Tôi là một ấm trà."
joshp

1
Một ví dụ là nhiều yêu cầu và phản hồi (theo đợt) . Batching không phải là một điều yên tĩnh; nhưng mối quan tâm về hiệu quả thực tế thường cần một số hỗ trợ cho việc xử lý hàng loạt các mối quan tâm về sự thanh lịch.
rwong

Câu trả lời:


35

Câu hỏi thú vị.

Về cơ bản, chúng ta có thể giảm điều này xuống đúng cách để phân loại mọi thứ theo cách tương tự với các lớp OSI. HTTP thường được định nghĩa là giao thức Cấp ứng dụng và HTTP thực sự là giao thức Máy khách / Máy chủ chung.

Tuy nhiên, trên thực tế, máy chủ hầu như luôn là một thiết bị chuyển tiếp và máy khách là trình duyệt web, chịu trách nhiệm phiên dịch và hiển thị nội dung: Máy chủ chỉ chuyển mọi thứ sang một ứng dụng tùy ý và các ứng dụng đó gửi lại các tập lệnh tùy ý mà trình duyệt chịu trách nhiệm thi hành. Bản thân tương tác HTTP - biểu mẫu yêu cầu / phản hồi, mã trạng thái, v.v. - chủ yếu là vấn đề về cách yêu cầu, phục vụ và hiển thị nội dung tùy ý một cách hiệu quả nhất có thể mà không bị cản trở. Nhiều mã trạng thái và tiêu đề thực sự được thiết kế cho các mục đích này.

Vấn đề với việc cố gắng cõng giao thức HTTP để xử lý các luồng cụ thể của ứng dụng, là bạn có một trong hai tùy chọn: 1) Bạn phải biến logic yêu cầu / phản hồi của mình thành một tập hợp con của các quy tắc HTTP; hoặc 2) Bạn phải sử dụng lại các quy tắc nhất định và sau đó việc phân tách các mối quan tâm có xu hướng trở nên mờ nhạt. Điều này có thể trông đẹp và sạch sẽ lúc đầu, nhưng tôi nghĩ đó là một trong những quyết định thiết kế mà bạn sẽ hối hận khi dự án của bạn phát triển.

Do đó, tôi muốn nói rằng tốt hơn là nên rõ ràng về việc tách các giao thức. Hãy để máy chủ HTTP và trình duyệt web làm việc của riêng họ và để ứng dụng làm việc riêng của mình. Ứng dụng cần có khả năng thực hiện các yêu cầu và ứng dụng cần các phản hồi - và logic của nó về cách yêu cầu, cách diễn giải các phản hồi, có thể phức tạp hơn (hoặc ít hơn) so với phối cảnh HTTP.

Lợi ích khác của phương pháp này, điều đáng nói, là các ứng dụng, nói chung, không nên phụ thuộc vào một giao thức vận chuyển cơ bản (theo quan điểm logic). Bản thân HTTP đã thay đổi trong quá khứ và bây giờ chúng tôi có HTTP 2, sau SPDY. Nếu bạn xem ứng dụng của mình không nhiều hơn một plugin chức năng HTTP, bạn có thể bị kẹt ở đó khi cơ sở hạ tầng mới tiếp quản.


8
Rất sâu sắc. Đối số mạnh nhất ở đây là sự không khớp (trở kháng) giữa mã trạng thái HTTP và giá trị trả về của ứng dụng. Điều này có thể trở thành một cơn ác mộng về lâu dài. Hơn nữa, tôi rất ủng hộ việc phân tách mối quan tâm giữa vận chuyển (HTTP) và tải trọng (dữ liệu ứng dụng). Nếu bạn nhập sai URL của điểm cuối dịch vụ, bạn sẽ nhận được 404. Nếu bạn yêu cầu dịch vụ cho một mục không tồn tại, bạn sẽ nhận được một tin nhắn dành riêng cho ứng dụng (có thể có thêm thông tin bạn có thể sử dụng để giải quyết vấn đề).

2
Nếu bạn gõ nhầm URL, bạn thậm chí có thể không đến đúng máy chủ, và sau đó bất cứ điều gì cũng có thể xảy ra.
gnasher729

Đây là một cái nhìn độc đáo sắc thái. Tôi nghĩ rằng vấn đề HTTP trở thành một lớp vận chuyển giả là vấn đề thực sự với việc đưa ra quyết định. Tôi thường gặp phải câu hỏi này khi bạn có máy chủ nginx hoặc apache ủy quyền máy chủ nodejs, nơi proxy đã có các quy tắc để gửi các mã này và câu hỏi đặt ra là liệu nó có phù hợp với phụ trợ để tuân thủ tiêu chuẩn hay không. Trong một số trường hợp đó, có thể có một lý do thiết kế để không gửi mã lỗi, vì nginx có thể hiểu nó là 'phụ trợ xuống'.
Kagan Mattson

4
Tôi đồng ý. Không có gì sai với lỗi lớp ứng dụng được báo cáo trong phản hồi HTTP 200. 200 chỉ ra rằng chính yêu cầu / phản hồi HTTP đã thành công, mà không nói bất cứ điều gì về nội dung của nó hoặc ngữ nghĩa của lớp ứng dụng đang được gọi vào thời điểm đó.
Cuộc đua nhẹ nhàng với Monica

22

Câu hỏi này là một chút ý kiến ​​dựa trên, nhưng một trong hai cách.

Theo cách tôi thấy, 200 có thể phục vụ "lỗi mềm". Khi nói đến việc xây dựng API, tôi cố gắng phân biệt giữa những lỗi này và "lỗi cứng".

"Lỗi mềm" sẽ được cung cấp với mã trạng thái 200, nhưng sẽ chứa mô tả lỗi và trạng thái thành công là false. "Lỗi mềm" sẽ chỉ xảy ra khi kết quả là "như mong đợi", nhưng không thành công theo nghĩa nghiêm ngặt nhất.

Điều quan trọng cần lưu ý là "lỗi mềm" là một gợi ý cho người thực hiện. Do đó, điều quan trọng là cũng cung cấp thêm thông tin về lỗi như thông báo lỗi có thể đọc được của con người và / hoặc một số loại mã có thể được sử dụng để cung cấp phản hồi cho người dùng cuối. Những lỗi này cung cấp cho người triển khai (và người dùng cuối) nhiều thông tin hơn về những gì đã xảy ra ở phía máy chủ .

Chẳng hạn, bạn có một API với chức năng tìm kiếm nhưng trong quá trình tìm kiếm, không có kết quả nào mang lại. Đây không phải là sai lầm, nhưng nó cũng không phải là "thành công", không phải theo nghĩa chặt chẽ nhất của định nghĩa.

Ví dụ được định dạng là JSON:

{
    "meta" {
        "success": false,
        "message": "Search yielded no results",
        "code": "NORESULTS"
    }
    "data": []
}

Mặt khác, "lỗi cứng" sẽ được cung cấp với mã trạng thái được khuyến nghị cho lỗi. Người dùng chưa đăng nhập? - 403 / 401. Đầu vào không đúng định dạng? - 400. Lỗi máy chủ? - 50X. Và như vậy.

Một lần nữa, đó là một chút dựa trên ý kiến. Một số người muốn xử lý tất cả các lỗi như nhau, "lỗi cứng" mọi thứ. Không có kết quả tìm kiếm? Đó là 404! Ở phía bên kia của đồng tiền, không có kết quả tìm kiếm? - Đây là như mong đợi, không có lỗi.

Một yếu tố quan trọng khác cần xem xét là kiến ​​trúc của bạn, ví dụ; nếu bạn tương tác với API bằng các yêu cầu JavaScript XHR và jQuery hoặc AngularJS. Những "lỗi cứng" này sẽ phải được xử lý bằng một cuộc gọi lại riêng, trong khi "lỗi mềm" có thể được xử lý bằng "thành công" -callback. Không phá vỡ bất cứ điều gì, kết quả vẫn là "như mong đợi". Mã phía khách hàng sau đó có thể xem trạng thái thành công và mã (hoặc tin nhắn). Và in nó cho người dùng cuối.


2
Trên thực tế, việc phân loại đó là một lỗi ở cấp độ API là một quyết định gây tò mò. Mặc dù khách hàng có thể, theo quyết định của mình, phân loại nó là bất ngờ ở cấp độ người dùng.
Ded repeatator

1
Có nhiều thứ phải được tính đến. Tất cả phụ thuộc vào việc triển khai API. Một lần nữa, một chút dựa trên quan điểm và cũng dựa trên những gì API định nghĩa là "thành công" và / hoặc "lỗi". Các "success": false-flag là một gợi ý cho người thực hiện rằng một cái gì đó lên. Thông thường nó nên đi với một mã trạng thái nội bộ . Mã "code": "NORESULTS"hoặc số - bất cứ điều gì người tạo ra các fancies API. Nó chủ yếu ở đó vì vậy bất cứ ai thực hiện API đều có thể khấu trừ thông tin về những gì đã xảy ra trên máy chủ.
chết

15

Có hai khía cạnh của API: Nỗ lực triển khai API và nỗ lực của tất cả các khách hàng sử dụng API một cách chính xác.

Là tác giả của khách hàng, tôi biết rằng khi tôi gửi yêu cầu đến máy chủ web, tôi có thể gặp lỗi (không bao giờ nói chuyện đúng với máy chủ) hoặc trả lời bằng mã trạng thái. Tôi phải xử lý các lỗi. Tôi phải xử lý một phản ứng tốt. Tôi phải xử lý các phản hồi dự kiến, ghi lại, "xấu". Tôi phải xử lý bất cứ điều gì khác trở lại.

Thiết kế API, bạn nên xem khách hàng dễ xử lý nhất. Nếu khách hàng gửi yêu cầu được định dạng tốt và bạn có thể thực hiện những gì yêu cầu yêu cầu bạn thực hiện, thì bạn nên đưa ra câu trả lời trong phạm vi 200 (có một số trường hợp số khác 200 trong phạm vi đó là phù hợp).

Nếu khách hàng yêu cầu "đưa cho tôi tất cả các hồ sơ như ...", và có 0, thì 200 với thành công và một mảng các bản ghi bằng 0 là hoàn toàn phù hợp. Các trường hợp mà bạn đề cập:

"Đăng nhập thất bại" thường là một số 401. "Không thể tìm thấy tệp" phải là 404. "Thiếu tham số x" phải là khoảng 500 (thực tế là 400 nếu máy chủ nhận ra rằng yêu cầu không tốt và 500 nếu máy chủ hoàn toàn bối rối trước yêu cầu của tôi và không biết chuyện gì đang xảy ra). Trả lại 200 trong những trường hợp này là vô nghĩa. Nó chỉ có nghĩa là tác giả của một khách hàng, tôi không thể chỉ nhìn vào mã trạng thái, tôi cũng phải nghiên cứu trả lời. Tôi không thể chỉ nói "trạng thái 200, tuyệt vời, đây là dữ liệu".

Đặc biệt là "thiếu tham số" - đó không phải là điều mà tôi sẽ xử lý . Nó có nghĩa là yêu cầu của tôi là không chính xác. Nếu yêu cầu của tôi không chính xác, tôi không có dự phòng để sửa yêu cầu không chính xác đó - tôi sẽ gửi yêu cầu chính xác để bắt đầu. Bây giờ tôi buộc phải xử lý nó. Tôi nhận được 200 và phải kiểm tra xem có thiếu "tham số" không. Cái đó ghê thật.

Cuối cùng, có một tá hoặc hai mã trạng thái để xử lý nhiều tình huống khác nhau và bạn nên sử dụng chúng.


3
Khi kết nối với API, cá nhân tôi thà nhận được 200 trên 'không tìm thấy tệp' khi kết nối với điểm cuối hợp lệ, vì khi đó việc xử lý HTTP của tôi không phải chảy vào lớp xử lý API ở trên cùng.
whatsisname

4
"Thiếu tham số x" phải là 400 BAD_REQUEST vì đó là ứng dụng khách làm sai. Nên dành 500 INTERNAL_SERVER_ERROR cho các trường hợp máy chủ đang làm sai. 500 ngụ ý rằng khách hàng có thể thử lại. Một 400 ngụ ý rằng ai đó nên đi sửa chữa khách hàng.
Gort Robot

1
Nếu bạn đang viết giao diện RESTful, URL sẽ xác định một đối tượng cụ thể và do đó 404 là phù hợp. Về mặt khái niệm, cùng một /customers/premium/johndoe.jsonđề cập đến một khách hàng không có trong cơ sở dữ liệu và nếu /files/morefiles/customers.htmlđề cập đến một trang không nằm trong hệ thống tập tin.
Gort Robot

@whatsisname Những gì bạn đang nói có ý nghĩa bởi vì sau đó không rõ liệu đó là điểm cuối xấu hay tài nguyên không tồn tại. Bạn cũng có thể lập luận rằng liệu điểm cuối có hợp lệ hay không, không có tài nguyên nào tồn tại tại địa chỉ đó vì vậy a 404là chính xác trong cả hai trường hợp.
Pete

2
Một điều mà tôi chưa thấy đề cập đến là khi bạn cõng lỗi ứng dụng vào mã trạng thái HTTP, bạn có thể mất thông tin. Nếu ứng dụng chỉ trả về 404 và không có gì khác, bạn không biết liệu đó là do API của bạn trả về 404 hay vì máy chủ không thể tìm thấy tệp. Điều đó có thể thêm một bước để gỡ lỗi của bạn.
AmadeusDrZaius
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.