Mã trạng thái HTTP cho phiên bản vẫn xử lý


47

Tôi đang xây dựng API RESTful hỗ trợ xếp hàng các tác vụ dài hạn để xử lý cuối cùng.

Quy trình công việc điển hình cho API này sẽ là:

  1. Người dùng điền vào mẫu
  2. Khách hàng đăng dữ liệu lên API
  3. API trả về 202 được chấp nhận
  4. Máy khách chuyển hướng người dùng đến một URL duy nhất cho yêu cầu đó ( /results/{request_id})
  5. ~ cuối cùng ~
  6. Khách hàng truy cập lại URL và xem kết quả trên trang đó.

Vấn đề của tôi là ở bước 6. Bất cứ khi nào người dùng truy cập trang, tôi sẽ gửi yêu cầu tới API ( GET /api/results/{request_id}) của mình. Lý tưởng nhất là nhiệm vụ sẽ được hoàn thành ngay bây giờ và tôi sẽ trả lại 200 OK với kết quả nhiệm vụ của họ.

Nhưng người dùng rất khó chịu và tôi mong đợi nhiều lần làm mới quá mức, khi kết quả vẫn chưa được xử lý xong.

Tùy chọn tốt nhất của tôi cho mã trạng thái là gì để chỉ ra rằng:

  • yêu cầu này tồn tại,
  • nó chưa được thực hiện
  • nhưng nó cũng không thất bại.

Tôi không mong đợi một mã duy nhất để truyền đạt tất cả điều đó, nhưng tôi thích thứ gì đó cho phép tôi vượt qua siêu dữ liệu thay vì để khách hàng mong đợi nội dung.

Có thể có ý nghĩa khi trả lại 202, vì điều đó sẽ không có ý nghĩa nào khác ở đây: đó là một GETyêu cầu, vì vậy không có gì có thể được "chấp nhận". Đó sẽ là một lựa chọn hợp lý?

Sự thay thế rõ ràng cho tất cả điều này - có chức năng, nhưng đánh bại một mục đích của mã trạng thái - sẽ luôn luôn bao gồm siêu dữ liệu:

200 OK

{
    status: "complete",
    data: {
        foo: "123"
    }
}

...hoặc là...

200 OK

{
    status: "pending"
}

Sau đó client-side, tôi sẽ (thở dài) switchtrên response.data.statusđể xác định xem các yêu cầu được hoàn thành.

Đây có phải là những gì tôi nên làm? Hoặc có một sự thay thế tốt hơn? Điều này chỉ cảm thấy Web 1.0 với tôi.


1
Không phải mã 1xx được thực hiện chính xác cho mục đích đó sao?
Andy

@Andy Tôi đã xem 102, nhưng đó là thứ dành cho WebDAV. Ngoài ra, không ... Chúng chủ yếu dành cho liên lạc quá cảnh. Hữu ích trong việc chuyển đổi sang Web Sockets và như vậy.
Matthew Haugen

Bạn đang nói về sự chậm trễ nào? 10 giây? Hay 6 giờ? Nếu độ trễ là ngắn và thường trong cùng một lượt truy cập trình duyệt, bạn có thể thực hiện bỏ phiếu dài hoặc ổ cắm web thay vì bỏ phiếu định kỳ.
GrandmasterB

@GrandmasterB Đó là giờ, có khả năng. Tôi không chịu trách nhiệm cho việc xử lý công việc, vì vậy tôi không có ước tính thực sự tốt, nhưng sẽ mất một thời gian. Nếu không, tôi sẽ để lại POSTyêu cầu đầu tiên mở. Vấn đề chính với việc bỏ phiếu dài hoặc ổ cắm web là người dùng có thể đóng trình duyệt và quay lại. Tôi có thể mở lại chúng vào thời điểm đó (và đó là những gì tôi làm), nhưng có vẻ như sẽ có một API duy nhất để gọi trước khi tôi mở các ổ cắm đó, vì đó là vấn đề phát sinh.
Matthew Haugen

Câu trả lời:


48

HTTP 202 được chấp nhận (HTTP / 1.1)

Bạn đang tìm kiếm HTTP 202 Acceptedtrạng thái. Xem RFC 2616 :

Yêu cầu đã được chấp nhận để xử lý, nhưng việc xử lý chưa được hoàn thành.

Xử lý HTTP 102 (WebDAV)

RFC 2518 đề nghị sử dụng HTTP 102 Processing:

Mã trạng thái 102 (Đang xử lý) là một phản hồi tạm thời được sử dụng để thông báo cho khách hàng rằng máy chủ đã chấp nhận yêu cầu hoàn chỉnh, nhưng vẫn chưa hoàn thành.

nhưng nó có một cảnh báo:

Máy chủ PHẢI gửi phản hồi cuối cùng sau khi yêu cầu được hoàn thành.

Tôi không chắc làm thế nào để giải thích câu cuối cùng. Máy chủ có nên tránh gửi bất cứ điều gì trong quá trình xử lý và chỉ phản hồi sau khi hoàn thành? Hoặc nó chỉ buộc kết thúc phản hồi chỉ khi quá trình xử lý chấm dứt? Điều này có thể hữu ích nếu bạn muốn báo cáo tiến độ. Gửi HTTP 102 và tuôn ra byte phản hồi theo byte (hoặc từng dòng).

Chẳng hạn, đối với một quá trình dài nhưng tuyến tính, bạn có thể gửi một trăm dấu chấm, xả sau mỗi ký tự. Nếu phía máy khách (chẳng hạn như ứng dụng JavaScript) biết rằng nó sẽ mong đợi chính xác 100 ký tự, thì nó có thể khớp với thanh tiến trình để hiển thị cho người dùng.

Một ví dụ khác liên quan đến một quá trình bao gồm một số bước phi tuyến tính. Sau mỗi bước, bạn có thể xóa một thông điệp tường trình cuối cùng sẽ được hiển thị cho người dùng, để người dùng cuối có thể biết quá trình đang diễn ra như thế nào.

Các vấn đề với xả nước lũy tiến

Lưu ý rằng trong khi kỹ thuật này có giá trị của nó, tôi sẽ không đề xuất nó . Một trong những lý do là nó buộc kết nối vẫn mở, điều này có thể ảnh hưởng đến tính khả dụng của dịch vụ và không mở rộng tốt.

Cách tiếp cận tốt hơn là phản hồi HTTP 202 Acceptedvà cho phép người dùng quay lại với bạn sau để xác định xem việc xử lý đã kết thúc hay chưa (ví dụ bằng cách gọi liên tục một URI đã cho, như /process/resultsẽ phản hồi với HTTP 404 Không tìm thấy hoặc Xung đột HTTP 409 cho đến khi quá trình xử lý kết thúc và kết quả đã sẵn sàng) hoặc thông báo cho người dùng khi quá trình xử lý được thực hiện nếu bạn có thể gọi lại máy khách thông qua dịch vụ xếp hàng tin nhắn ( ví dụ ) hoặc WebSockets.

Ví dụ thực tế

Hãy tưởng tượng một dịch vụ web chuyển đổi video. Điểm vào là:

POST /video/convert

trong đó lấy một tệp video từ yêu cầu HTTP và thực hiện một số phép thuật với nó. Chúng ta hãy tưởng tượng rằng phép thuật này rất tốn CPU, vì vậy nó không thể được thực hiện trong thời gian thực trong quá trình chuyển yêu cầu. Điều này có nghĩa là một khi tệp được chuyển, máy chủ sẽ phản hồi với một HTTP 202 Acceptedsố nội dung JSON, nghĩa là có Có, tôi đã nhận được video của bạn và tôi đang làm việc với nó; nó sẽ sẵn sàng ở đâu đó trong tương lai và sẽ có sẵn thông qua ID 123.

Khách hàng có khả năng đăng ký hàng đợi tin nhắn để được thông báo khi quá trình xử lý kết thúc. Sau khi kết thúc, khách hàng có thể tải xuống video đã xử lý bằng cách truy cập:

GET /video/download/123

dẫn đến một HTTP 200.

Điều gì xảy ra nếu máy khách truy vấn URI này trước khi nhận được thông báo? Chà, máy chủ sẽ phản hồi HTTP 404vì, thực sự, video chưa tồn tại. Nó có thể được chuẩn bị hiện tại. Nó có thể không bao giờ được yêu cầu. Nó có thể tồn tại một thời gian trong quá khứ và được gỡ bỏ sau đó. Tất cả vấn đề là video kết quả không có sẵn.

Bây giờ, điều gì sẽ xảy ra nếu khách hàng quan tâm không chỉ về video cuối cùng mà còn về tiến trình (điều này thậm chí còn quan trọng hơn nếu không có dịch vụ xếp hàng tin nhắn hoặc bất kỳ cơ chế tương tự nào)?

Trong trường hợp này, bạn có thể sử dụng điểm cuối khác:

GET /video/status/123

mà sẽ dẫn đến một phản ứng tương tự như thế này:

HTTP 200
{
    "id": 123,
    "status": "queued",
    "priority": 2,
    "progress-percent": 0,
    "submitted-utc-time": "2016-04-19T13:59:22"
}

Thực hiện yêu cầu nhiều lần sẽ cho thấy tiến trình cho đến khi:

HTTP 200
{
    "id": 123,
    "status": "done",
    "progress-percent": 100,
    "submitted-utc-time": "2016-04-19T13:59:22"
}

Điều rất quan trọng để tạo sự khác biệt giữa ba loại yêu cầu:

  • POST /video/convertxếp hàng một nhiệm vụ. Nó chỉ được gọi một lần: gọi lại sẽ xếp hàng một nhiệm vụ bổ sung.
  • GET /video/download/123liên quan đến kết quả của hoạt động: tài nguyên là video. Việc xử lý điều đó là những gì đã xảy ra dưới mui xe để chuẩn bị kết quả thực tế trước khi yêu cầu và độc lập với yêu cầu, điều này không liên quan ở đây. Nó có thể được gọi một lần hoặc nhiều lần.
  • GET /video/status/123liên quan đến việc xử lý mỗi se . Nó không xếp hàng gì cả. Nó không quan tâm đến video kết quả. Tài nguyên là chính nó xử lý. Nó có thể được gọi một lần hoặc nhiều lần.

1
Liệu một 202 có ý nghĩa trong việc đáp ứng với một GET, mặc dù? Đó chắc chắn là lựa chọn chính xác cho ban đầu POST, đó là lý do tại sao tôi sử dụng nó. Nhưng có vẻ nghi ngờ về mặt ngữ nghĩa đối với GETviệc nói "chấp nhận" khi nó không chấp nhận bất cứ điều gì từ yêu cầu cụ thể đó.
Matthew Haugen

2
@MainMa Giống như tôi đã nói, tôi POSTlên công việc để được xếp hàng, sau đó tôi GETkết quả, có khả năng sau khi khách hàng đã đóng phiên. 404 là một cái gì đó tôi đã xem xét là tốt, nhưng có vẻ như sai, vì yêu cầu được tìm thấy, nó chỉ chưa được hoàn thành. Điều đó sẽ cho tôi thấy rằng công việc xếp hàng không được tìm thấy, đó là một tình huống rất khác.
Matthew Haugen

1
@MatthewHaugen: khi bạn thực hiện GETphần này, đừng nghĩ về nó như một yêu cầu không đầy đủ , mà là một yêu cầu để có được kết quả của hoạt động . Chẳng hạn, nếu tôi bảo bạn chuyển đổi video và bạn phải mất năm phút để thực hiện, yêu cầu một video được chuyển đổi hai phút sau sẽ dẫn đến HTTP 404, vì đơn giản là video chưa có. Mặt khác, yêu cầu tiến trình của hoạt động có thể sẽ dẫn đến HTTP 200 chứa số byte được chuyển đổi, tốc độ, v.v.
Arseni Mourzenko

5
Mã trạng thái HTTP cho tài nguyên chưa khả dụng đề xuất trả về phản hồi xung đột 409 ("Không thể hoàn thành yêu cầu do xung đột với trạng thái hiện tại của tài nguyên."), Thay vì phản hồi 404, trong trường hợp tài nguyên không 'T tồn tại bởi vì nó đang ở giữa được tạo ra.
Brian

1
@Brian Nhận xét của bạn sẽ đưa ra câu trả lời hợp lý cho câu hỏi này. Mặc dù sau đó tôi sẽ trả lời với "[t] mã của anh ấy 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", điều đó không đúng trong trường hợp của tôi, nhưng dường như điều đó ít sai hơn "không tìm thấy." Một phần của tôi đang nghiêng về phía 409 với tiêu đề Retry-After được ghim vào. Vấn đề duy nhất là có vẻ kỳ lạ khi trả lại 409 cho một GET, nhưng tôi có thể sống với sự kỳ lạ đó - không có khả năng được định nghĩa khác trong tương lai.
Matthew Haugen

5

Sự thay thế rõ ràng cho tất cả điều này - có chức năng, nhưng đánh bại một mục đích của mã trạng thái - sẽ luôn luôn bao gồm siêu dữ liệu:

Đây là cách chính xác để đi. Trạng thái tài nguyên liên quan đến nhật ký cụ thể của miền (còn gọi là logic nghiệp vụ) là một vấn đề đối với loại nội dung của đại diện của tài nguyên.

Có hai khái niệm khác nhau được đưa ra ở đây thực sự khác nhau. Một là trạng thái chuyển trạng thái giữa máy khách và máy chủ của tài nguyên và trạng thái khác là trạng thái của chính tài nguyên đó trong bối cảnh mà miền kinh doanh đảm nhận các trạng thái khác nhau của tài nguyên đó. Cái sau không liên quan gì đến mã trạng thái HTTP.

Hãy nhớ mã trạng thái HTTP tương ứng với chuyển trạng thái giữa máy khách và máy chủ của tài nguyên đang được xử lý, độc lập với bất kỳ chi tiết nào của tài nguyên đó. Khi bạn sử dụng GETtài nguyên, máy khách của bạn đang yêu cầu máy chủ thể hiện tài nguyên ở trạng thái hiện tại. Đó có thể là hình ảnh của một con chim, nó có thể là một tài liệu Word, nó có thể là temp bên ngoài hiện tại. Giao thức HTTP không quan tâm. Mã trạng thái HTTP tương ứng với kết quả của yêu cầu đó. Có phải POSTtừ máy khách đến máy chủ đã chuyển tài nguyên đến máy chủ, nơi máy chủ sau đó đã cung cấp cho nó một URL mà máy khách có thể xem? Đúng? Sau đó, đó là một 201 Createdphản ứng.

Tài nguyên có thể là một đặt vé máy bay hiện đang ở trạng thái 'được xem xét'. Hoặc đó có thể là đơn đặt hàng mua sản phẩm ở trạng thái 'được phê duyệt'. Các trạng thái đó là miền cụ thể và không phải là giao thức HTTP. Giao thức HTTP liên quan đến việc chuyển tài nguyên giữa máy khách và máy chủ.

Điểm quan trọng của REST và HTTP là các giao thức không liên quan đến các chi tiết của tài nguyên. Đây là mục đích, nó không liên quan đến các vấn đề cụ thể của tên miền để có thể sử dụng nó mà không cần phải biết gì về các vấn đề cụ thể của tên miền. Bạn không diễn giải lại ý nghĩa của mã trạng thái HTTP trong từng bối cảnh khác nhau (hệ thống đặt vé máy bay, hệ thống xử lý tưởng tượng, hệ thống bảo mật video, v.v.).

Các công cụ cụ thể của miền là để máy khách và máy chủ tự tìm ra giữa chúng dựa trên Content Typetài nguyên. Giao thức HTTP không tin vào điều này.

Đối với cách khách hàng nhận ra rằng tài nguyên Yêu cầu đã thay đổi trạng thái, bỏ phiếu là đặt cược tốt nhất của bạn vì nó giữ quyền kiểm soát tại máy khách và không giả định kết nối không bị gián đoạn. Đặc biệt nếu nó sẽ có khả năng hàng giờ cho đến khi nhà nước thay đổi. Ngay cả khi bạn nói với địa ngục với REST, bạn sẽ giữ kết nối mở, giữ cho nó mở trong nhiều giờ và cho rằng không có gì sai sẽ là một ý tưởng tồi. Điều gì xảy ra nếu người dùng đóng máy khách hoặc mạng bị tắt. Nếu độ chi tiết là giờ, khách hàng chỉ có thể yêu cầu trạng thái cứ sau vài phút cho đến khi Yêu cầu thay đổi từ 'đang chờ xử lý' thành 'xong'.

Hy vọng rằng sẽ giúp làm rõ mọi thứ


"POST từ máy khách đến máy chủ có chuyển tài nguyên sang máy chủ không, nơi máy chủ sau đó đã cung cấp cho nó một URL mà máy khách có thể xem? Có? Sau đó, đó là phản hồi 201 Tạo." 202 Chấp nhận cũng được chấp nhận như là một phản ứng với điều này nếu máy chủ không thể hành động ngay lập tức để xử lý tài nguyên, đó là những gì OP đang làm.
Andy

1
Có điều là máy chủ đang hành động ngay lập tức. Nó tạo ra tài nguyên với một URL ngay lập tức. Nó chỉ là trạng thái của tài nguyên là "Đang chờ xử lý" (hoặc một cái gì đó). Đó là một trạng thái kinh doanh. Theo như Giao thức HTTP, máy chủ đã hành động ngay khi nó tạo tài nguyên và cung cấp cho khách hàng URL của tài nguyên. Bạn có thể NHẬN tài nguyên đó. Bản thân yêu cầu POST không chờ xử lý. Đây là những gì tôi muốn nói bằng cách giữ hai miền khái niệm khác nhau. Nếu khách hàng đang gửi một đám cháy và quên yêu cầu POST không được thực hiện trong nhiều giờ thì 202 sẽ được áp dụng.
Cormac Mulhall

Không ai quan tâm nếu url tồn tại nhưng bạn không thể lấy dữ liệu mà tài nguyên đại diện vì nó vẫn đang được xử lý. Cũng có thể KHÔNG tạo url cho đến khi nó có thể được sử dụng để lấy video.
Andy

Tài nguyên được tạo ra, nó chỉ ở trạng thái "đang chờ xử lý". Đó là trong chính dữ liệu có liên quan. Tại một thời điểm nào đó trong tương lai, máy chủ có thể thay đổi trạng thái tài nguyên thành "đã hoàn thành" (hoặc "không thành công") nhưng đó là một khái niệm khác với nhiệm vụ cụ thể của miền HTTP là "tạo tài nguyên". Đang chờ xử lý có thể là trạng thái hoàn toàn hợp lệ đối với tài nguyên "Yêu cầu" và khách hàng rõ ràng muốn biết máy chủ đã tạo tài nguyên ở trạng thái đó vì nó chuyển từ yêu cầu máy chủ tạo tài nguyên để biết việc bỏ phiếu để tìm hiểu nếu nhà nước thay đổi.
Cormac Mulhall

4

Tôi thấy các đề xuất từ ​​blog này hợp lý: REST và các công việc dài hạn .

Để tóm tắt:

  1. Máy chủ trả về mã "202 Được chấp nhận" với tiêu đề "Vị trí" được đặt thành URI cho máy khách để kiểm tra trạng thái, ví dụ: "/ queue / 12345".
  2. Cho đến khi quá trình xử lý kết thúc, máy chủ sẽ trả lời các truy vấn trạng thái với "200 OK" và một số dữ liệu phản hồi hiển thị trạng thái công việc.
  3. Sau khi quá trình xử lý kết thúc, máy chủ sẽ trả lời các truy vấn trạng thái với "303 Xem khác" và "Vị trí" có chứa URI cho kết quả cuối cùng.

2

Mã trạng thái HTTP cho Tài nguyên chưa khả dụng đề xuất trả về phản hồi xung đột 409, thay vì phản hồi 404, trong trường hợp tài nguyên không tồn tại vì nó đang được tạo.

Từ thông số w3 :

10,4.10 409 Xung đột

Yêu cầu không thể được hoàn thành do xung đột với trạng thái hiện tại của tài nguyên. Mã này 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. Cơ quan phản hồi NÊN bao gồm đủ

thông tin để người dùng nhận ra nguồn gốc của xung đột. Lý tưởng nhất, thực thể phản hồi sẽ bao gồm đủ thông tin cho người dùng hoặc tác nhân người dùng để khắc phục sự cố; tuy nhiên, điều đó có thể là không thể và không bắt buộc.

Xung đột rất có thể xảy ra để đáp ứng yêu cầu PUT. Ví dụ: nếu phiên bản đang được sử dụng và thực thể là PUT bao gồm các thay đổi đối với tài nguyên xung đột với tài nguyên được tạo bởi yêu cầu trước đó (bên thứ ba), máy chủ có thể sử dụng phản hồi 409 để cho biết rằng nó không thể hoàn thành yêu cầu . Trong trường hợp này, thực thể phản hồi có thể sẽ chứa một danh sách các khác biệt giữa hai phiên bản theo định dạng được xác định bởi Kiểu nội dung phản hồi.

Điều này hơi khó xử, vì mã 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." Tôi đề nghị cơ quan phản hồi bao gồm một thông báo (có thể ở một số định dạng phản hồi khớp với phần còn lại của API của bạn) như: "Tài nguyên này hiện đang được tạo. Nó được khởi tạo vào [TIME] và được ước tính hoàn thành vào [TIME]. Vui lòng thử lại sau."

Lưu ý rằng tôi chỉ đề xuất cách tiếp cận 409 nếu rất có khả năng người dùng đang yêu cầu tài nguyên cũng là người dùng đã khởi tạo việc tạo tài nguyên đó. Người dùng không liên quan đến việc tạo tài nguyên sẽ thấy lỗi 404 ít gây nhầm lẫn hơn.


Có vẻ như một sự kéo dài cho những gì 409 thực sự có ý nghĩa, đó là để đáp ứng với một đặt.
Andy

@Andy: Đúng, nhưng mọi sự thay thế khác cũng vậy. Ví dụ, 202 thực sự có nghĩa là một phản hồi cho yêu cầu bắt đầu xử lý, không phải là yêu cầu yêu cầu kết quả xử lý. Thực sự, phản hồi tuân thủ theo thông số kỹ thuật nhất là 404, vì tài nguyên không được tìm thấy (vì nó chưa tồn tại). Không có gì ngăn API cung cấp dữ liệu api có liên quan trong phản hồi 404. Hãy nhớ rằng, các phản hồi 4xx / 5xx có xu hướng gây khó chịu khi sử dụng; một số ngôn ngữ sẽ kích hoạt một ngoại lệ thay vì chỉ cung cấp một mã trạng thái khác.
Brian

2
Không, đặc biệt là vài đoạn cuối của câu trả lời của MainMa. Các điểm kết thúc riêng biệt để kiểm tra trạng thái của yêu cầu và để nhận video. Trạng thái không phải là tài nguyên giống như video và phải có địa chỉ riêng.
Andy
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.