HATEOAS: URL tuyệt đối hay tương đối?


Câu trả lời:


83

Có một sự mơ hồ về khái niệm tinh tế khi mọi người nói "URI tương đối".

Theo định nghĩa của RFC3986 , một URI chung chứa:

  URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

  hier-part   = "//" authority path-abempty
              / path-absolute
              / path-rootless
              / path-empty

     foo://example.com:8042/over/there?name=ferret#nose
     \_/   \______________/\_________/ \_________/ \__/
      |           |            |            |        |
   scheme     authority       path        query   fragment

Điều khó khăn là, khi lược đồ và quyền hạn bị bỏ qua, bản thân phần "đường dẫn" có thể là một đường dẫn tuyệt đối (bắt đầu bằng /) hoặc một đường dẫn tương đối "không có gốc". Ví dụ:

  1. Một URI tuyệt đối hoặc một URI đầy đủ:"http://example.com:8042/over/there?name=ferret"
  2. Và đây là một đường đi tiểu tương đối, với đường dẫn tuyệt đối :/over/there
  3. Và đây là một đường đi tiểu tương đối, với đường dẫn tương đối : herehoặc ./herehoặc ../herehoặc v.v.

Vì vậy, nếu câu hỏi là "liệu một máy chủ có nên tạo ra đường dẫn tương đối trong phản hồi ổn định hay không", câu trả lời là "Không" và lý do chi tiết có sẵn ở đây . Tôi nghĩ rằng hầu hết mọi người (bao gồm cả tôi) chống lại "URI tương đối" thực sự chống lại "đường dẫn tương đối".

Và trên thực tế, hầu hết khung công tác MVC phía máy chủ có thể dễ dàng tạo URI tương đối với đường dẫn tuyệt đối, chẳng hạn như /absolute/path/to/the/controller, và câu hỏi trở thành "liệu việc triển khai máy chủ có nên đặt tiền tố a scheme://hostname:porttrước đường dẫn tuyệt đối hay không". Giống như câu hỏi của OP. Tôi không hoàn toàn chắc chắn về điều này.

Mặt khác, tôi vẫn nghĩ rằng máy chủ trả lại một tiểu đầy đủ là điều nên làm. Tuy nhiên, máy chủ không bao giờhostname:port nên mã hóa những thứ bên trong mã nguồn như thế này (nếu không, tôi muốn dự phòng cho nó tương đối với đường dẫn tuyệt đối). Giải pháp là phía máy chủ luôn lấy tiền tố đó từ tiêu đề "Máy chủ lưu trữ" của yêu cầu HTTP. Tuy nhiên, không chắc liệu điều này có hiệu quả với mọi tình huống hay không.

Mặt khác, có vẻ như không rắc rối lắm cho khách hàng khi nối http://example.com:8042đường dẫn tuyệt đối và. Rốt cuộc, máy khách đã biết sơ đồ và tên miền đó khi nó gửi yêu cầu đến máy chủ phải không?

Nói chung, tôi muốn nói, khuyên bạn nên sử dụng URI tuyệt đối, có thể là dự phòng cho URI tương đối với đường dẫn tuyệt đối, không bao giờ sử dụng đường dẫn tương đối .


2
Đây là một câu trả lời hay (+1) mà tôi đồng ý với ngoại trừ kết luận cuối cùng. Tuy nhiên, trong câu trả lời của mình, tôi lập luận rằng thông số HTTP xác định, ví dụ , "tuyệt đối" để chỉ một đường dẫn tuyệt đối , không phải là một URI đủ điều kiện. Vì vậy, tôi không đồng ý với (2) của bạn - nó một URI tuyệt đối, nhưng một URI mà máy khách phải suy ra giao thức mạng và máy chủ lưu trữ, vì vậy nó không phải là URI đủ điều kiện. Và do đó, tôi cũng không đồng ý với định nghĩa của bạn về (1) là cả URI đầy đủ và URI tuyệt đối.
Lawrence Dol

Cảm ơn đã nhận xét. Tôi chỉ mượn khái niệm đường dẫn tuyệt đối và đường dẫn tương đối từ hệ thống tệp. Ngoài các thuật ngữ khác nhau, tôi không thấy sự khác biệt đáng kể giữa ý kiến ​​của bạn và của tôi. Bạn cũng đề xuất hình thức 1 & 2, và bạn chống lại hình thức 3, phải không?
RayLuo

2
Thực tế mà nói, tôi dành cho (2); Tôi nghĩ (1) yêu cầu phần phụ trợ phải có nhiều kiến ​​thức cụ thể về HTTP (nghĩa là về các chi tiết của môi trường HTTP cụ thể, không phải HTTP nói chung) và (3) dường như yêu cầu quá nhiều ở máy khách. Tuy nhiên , lý do của tôi dựa trên thông số kỹ thuật của bản nháp ban đầu và các ví dụ đã được thay đổi trong phiên bản mới hơn theo cách làm mất hiệu lực lý luận của tôi.
Lawrence Dol

Cá nhân tôi chưa (chưa) tin rằng HATEOAS, và do đó nhu cầu trả lại các URI có ý nghĩa rất lớn đối với một API. Tôi chỉ không thấy các API của mình được điều khiển trên máy khách giống như cách duyệt một trang web; các trường hợp sử dụng dường như rất được thúc đẩy bởi hàm adhoc.
Lawrence Dol

@LawrenceDol Tôi cũng có sự nhầm lẫn về HATEOAS lúc đầu. Bây giờ tôi coi nó như một vấn đề của sự lựa chọn. Khách hàng của bạn chắc chắn có thể sử dụng hàm adhoc để sử dụng api của bạn, nhưng nếu họ / bạn muốn, họ / bạn vẫn có thể phát triển một mẫu để họ làm theo, do đó khách hàng sẽ không cần phải mã hóa từng url chính xác. Đó là HATEOAS.
RayLuo

13

Nó phụ thuộc vào người đang viết mã khách hàng. Nếu bạn đang viết máy khách và máy chủ thì nó không tạo ra nhiều khác biệt. Bạn sẽ phải chịu đựng những khó khăn khi xây dựng các URL trên máy khách hoặc trên máy chủ.

Tuy nhiên, nếu bạn đang xây dựng máy chủ và bạn mong đợi người khác viết mã máy khách thì họ sẽ yêu thích bạn hơn nhiều nếu bạn cung cấp các URI hoàn chỉnh. Giải quyết các URI tương đối có thể hơi phức tạp. Trước tiên, cách bạn giải quyết chúng phụ thuộc vào loại phương tiện được trả về. Html có thẻ cơ sở, Xml có thể có các thẻ xml: base trong mọi phần tử lồng nhau, nguồn cấp dữ liệu Atom có ​​thể có một cơ sở trong nguồn cấp dữ liệu và một cơ sở khác trong nội dung. Nếu bạn không cung cấp cho khách hàng của mình thông tin rõ ràng về URI cơ sở thì họ phải lấy URI cơ sở từ URI yêu cầu hoặc có thể từ tiêu đề Nội dung-Vị trí! Và hãy coi chừng đó là dấu gạch chéo. URI cơ sở được xác định bằng cách bỏ qua tất cả các ký tự ở bên phải của dấu gạch chéo cuối cùng. Điều này có nghĩa là dấu gạch chéo bây giờ rất quan trọng khi giải quyết các URI tương đối.

Vấn đề duy nhất khác cần được đề cập nhỏ là kích thước tài liệu. Nếu bạn đang trả lại một danh sách lớn các mục trong đó mỗi mục có thể có nhiều liên kết, việc sử dụng URL tuyệt đối có thể thêm một lượng byte đáng kể vào đối tượng của bạn nếu bạn không nén đối tượng. Đây là một vấn đề hoàn hảo và bạn cần quyết định xem liệu nó có quan trọng hay không trong từng trường hợp.


11

Sự khác biệt thực sự duy nhất dường như sẽ dễ dàng hơn cho khách hàng nếu họ đang sử dụng các URI tuyệt đối thay vì phải xây dựng chúng từ phiên bản tương đối. Tất nhiên, sự khác biệt đó sẽ đủ để khiến tôi phải lắc lư để làm được phiên bản tuyệt đối.


7

Khi ứng dụng của bạn mở rộng quy mô, bạn có thể muốn thực hiện cân bằng tải, vượt qua lỗi, v.v. Nếu bạn trả về URI tuyệt đối thì các ứng dụng phía máy khách của bạn sẽ tuân theo cấu hình máy chủ đang phát triển của bạn.


Miễn là bạn xác định "tuyệt đối" là đường dẫn tuyệt đối (ví dụ /xxx/yyy...) và không có nghĩa là một URI đủ điều kiện (ví dụ http://api.example.com/xxx/yyy...).
Lawrence Dol

6

Sử dụng bộ ba của RayLou mà tổ chức của tôi đã chọn để ủng hộ (2). Lý do chính là để tránh các cuộc tấn công XSS (Cross-Site Scripting). Vấn đề là, nếu kẻ tấn công có thể đưa URL gốc của chính họ vào phản hồi đến từ máy chủ, thì các yêu cầu tiếp theo của người dùng (chẳng hạn như yêu cầu xác thực với tên người dùng và mật khẩu) có thể được chuyển tiếp đến máy chủ của chính kẻ tấn công *.

Một số đã đưa ra vấn đề có thể chuyển hướng yêu cầu đến các máy chủ khác để cân bằng tải, nhưng (trong khi đó không phải là lĩnh vực chuyên môn của tôi), tôi cá rằng có nhiều cách tốt hơn để bật cân bằng tải mà không cần phải chuyển hướng rõ ràng các máy khách đến các vật chủ.

* vui lòng cho tôi biết nếu có bất kỳ sai sót nào trong dòng lập luận này. Tất nhiên, mục tiêu không phải là ngăn chặn tất cả các cuộc tấn công, mà là ít nhất một con đường tấn công.


Rất vui vì câu trả lời trước đây của tôi hữu ích cho tổ chức của bạn. Vâng, cá nhân tôi cũng thích (2), hay còn gọi là đường dẫn tuyệt đối ít lược đồ hơn. Tuy nhiên tôi tò mò về lý do của bạn. Làm cách nào để bạn thực thi khách hàng của mình chỉ chấp nhận url ít lược đồ của bạn? Một ứng dụng khách chung, chẳng hạn như một trình duyệt, sẽ không từ chối một url ít lược đồ. Vì vậy, tôi giả sử bạn sẽ phải viết mã phía máy khách của riêng mình để xác thực các url trước khi thực sự theo dõi chúng? Mặc dù điều đó có thể làm được về mặt kỹ thuật (nhưng không nhất thiết phải hữu ích), loại xác thực phía máy khách này thường không phải là một phần của cuộc thảo luận REST hoặc HATEOAS.
RayLuo

3
Tôi biết đây là một bài đăng cũ, nhưng tôi chỉ muốn chỉ ra rằng "nếu kẻ tấn công có thể đưa URL gốc của chính họ vào phản hồi quay lại" là một lý do vớ vẩn. Nếu họ có thể "đưa URL của chính họ" vào đúng vị trí trong câu trả lời, tôi cá rằng họ có thể, dễ dàng chỉ cần thay thế tên máy chủ của bạn bằng tên riêng của họ. Vì vậy, từ quan điểm bảo mật, tôi không thấy nó là một đối số hợp lệ.
Magnus Eriksson

5

Bạn nên luôn sử dụng URL đầy đủ. Nó hoạt động như một số nhận dạng duy nhất cho tài nguyên vì tất cả các URL đều được yêu cầu là duy nhất.

Tôi cũng sẽ tranh luận rằng bạn nên nhất quán. Vì tiêu đề HTTP vị trí mong đợi một URL đầy đủ dựa trên đặc tả HTTP, nên URL đầy đủ sẽ được gửi lại trong tiêu đề Vị trí cho máy khách khi tài nguyên mới được tạo. Sẽ rất lạ nếu bạn cung cấp một URL đầy đủ trong tiêu đề Vị trí và sau đó là các URI tương đối trong các liên kết trong nội dung phản hồi của bạn.


1
Vâng, thông số HTTP cho tiêu đề Vị trí cho biết URI tuyệt đối. Một URI tuyệt đối phải chứa một lược đồ (ví dụ: http).
Mark Bober

Nhưng câu hỏi không phải là làm thế nào để xây dựng các mã nhận dạng không rõ ràng theo ngữ cảnh , mà nó hỏi làm thế nào để xây dựng các liên kết . Sau đó có thể suy luận đúng "tại cùng một vị trí mạng với tài liệu này", và đó chính xác là những gì ví dụ về Locationtiêu đề của thông số đưa ra - một URI tuyệt đối không chứa lược đồ URI hoặc vị trí mạng của máy chủ. Mặc dù các liên kết và ID thường được kết hợp nhưng chúng không giống nhau - cái trước có ngữ cảnh, cái sau thì không.
Lawrence Dol

Bạn có thể gửi liên kết đến phần thông số kỹ thuật mà bạn đang nói đến không?
Mark Bober

Một URI tuyệt đối chỉ định một lược đồ; một URI không tuyệt đối được cho là tương đối. URI cũng được phân loại tùy theo độ mờ đục hoặc thứ bậc. URI không rõ ràng là một URI tuyệt đối có phần dành riêng cho lược đồ không bắt đầu bằng ký tự gạch chéo ('/'). Các URI mờ không phải phân tích cú pháp thêm. Một số ví dụ về URI không rõ ràng là: mailto: java-net@java.sun.com news: comp.lang.java urn: isbn: 096139210x
Mark Bober

1
Này, đừng lo lắng. Một điểm khác về công cụ này là tôi đã thấy mọi người sử dụng hrefs làm ID. Vì vậy, khách hàng không cần phải tạo lại URL từ một số tệp cấu hình và một id, nó chỉ biết URL và có thể lưu vào bộ nhớ cache dựa trên đó.
Mark Bober

2

Một cân nhắc quan trọng trong các kết quả API lớn là chi phí mạng bổ sung khi bao gồm nhiều lần toàn bộ URI. Bạn có tin hay không, nhưng gzip không hoàn toàn giải quyết được vấn đề này (không chắc tại sao). Chúng tôi đã bị sốc về lượng không gian mà URI đầy đủ đã chiếm khi có hàng trăm liên kết được đưa vào một kết quả.


2

Một hạn chế của việc sử dụng URI tuyệt đối là api không thể được ủy quyền.

Rút lại nó ... không đúng. Bạn nên tìm một URL đầy đủ bao gồm cả miền.


3
Tại sao URI tuyệt đối không thể sử dụng tên máy chủ của proxy?
Ed Summers

1
Đang giải quyết vấn đề chính xác này. Chúng tôi muốn tất cả các yêu cầu phải đi qua một loại lớp "cân bằng tải" trước. Các URI tuyệt đối tới các máy chủ trực tiếp sẽ phá vỡ mô hình này.
mag382

1
Tôi đang sử dụng Nginx để proxy một trang web có URL tuyệt đối. Nó hoàn toàn có khả năng thay thế URL phụ trợ bằng URL proxy tương đương. Cụ thể, đó là proxy windroad.artifactoryonline.com (có các URL đủ điều kiện và chuyển hướng đủ điều kiện) đến repo.windyroad.com.au
Tom Howard

2

Về ưu điểm, tôi thấy việc giảm số byte được truyền với chi phí xử lý thêm theo yêu cầu của khách hàng đối với đường dẫn (tuyệt đối). Nếu bạn cố gắng tiết kiệm từng byte, ngay cả sau khi thử mã hóa nội dung dưới dạng gzip, sử dụng đúng tiêu đề bộ nhớ đệm, sử dụng thẻ etags và các yêu cầu có điều kiện trên máy khách, thì điều này cuối cùng có thể là cần thiết, nhưng tôi mong đợi lợi nhuận cao hơn nhiều. nỗ lực của bạn khác.

Về nhược điểm, tôi thấy mất quyền kiểm soát về cách bạn có thể điều hướng luồng khách hàng giữa các tài nguyên trong tương lai (cân bằng tải, thử nghiệm A / B, ...) và tôi sẽ coi đó là một phương pháp không tốt khi quản lý web API. URL bạn cung cấp về cơ bản không còn mờ đục đối với máy khách (xem Tim Berners-Lee Tiên đề về Kiến trúc Web về độ mờ của URI ). Cuối cùng, bạn có trách nhiệm giữ cho khách hàng hài lòng về cách sử dụng sáng tạo của họ đối với API của bạn, ngay cả khi nó chỉ liên quan đến cấu trúc không gian URL của bạn. Nếu bạn cần cho phép sửa đổi URL được xác định rõ ràng, hãy xem xét việc sử dụng các mẫu URI như được sử dụng trong Ngôn ngữ ứng dụng siêu văn bản .

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.