Khi thiết kế một Dịch vụ Web RESTful bằng HATEOAS, ưu và nhược điểm của việc hiển thị một liên kết dưới dạng một URL hoàn chỉnh (" http: // server: port / application / customer / 1234 ") so với chỉ đường dẫn ("/ application / khách hàng / 1234 ")?
Khi thiết kế một Dịch vụ Web RESTful bằng HATEOAS, ưu và nhược điểm của việc hiển thị một liên kết dưới dạng một URL hoàn chỉnh (" http: // server: port / application / customer / 1234 ") so với chỉ đường dẫn ("/ application / khách hàng / 1234 ")?
Câu trả lời:
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ụ:
"http://example.com:8042/over/there?name=ferret"
/over/there
here
hoặc ./here
hoặc ../here
hoặ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:port
trướ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 .
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.
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.
/xxx/yyy...
) và không có nghĩa là một URI đủ điều kiện (ví dụ http://api.example.com/xxx/yyy...
).
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.
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.
Location
tiê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.
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ả.
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.
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 .