Có một số similar question trên SO, nhưng nó không được viết tốt và thiếu chi tiết. Vì vậy, tôi đang cố gắng viết một câu hỏi hay hơn.Làm cách nào để triển khai ứng dụng khách liên kết sâu trên máy chủ HATEOAS?
Tôi quan tâm đến cách triển khai HATEOAS với một ứng dụng trang đơn (SPA) đang sử dụng pushState
. Tôi muốn giữ liên kết sâu để người dùng có thể đánh dấu các URL trong SPA và truy cập lại chúng sau hoặc chia sẻ chúng với những người dùng khác.
Để cụ thể, tôi sẽ trình bày một ví dụ giả định. Ứng dụng trang đơn của tôi được lưu trữ tại https://www.hypothetical.com/
. Khi người dùng truy cập URL này trong trình duyệt, nó sẽ tải xuống SPA và bootstraps. SPA xem xét số location.href
hiện tại của trình duyệt để tìm ra tài nguyên API nào cần tìm nạp và hiển thị. Trong trường hợp của URL gốc, nó yêu cầu https://api.hypothetical.com/
, mà làm cho một phản ứng như thế này:
{
"employees": "https://api.hypothetical.com/employees/",
"offices": "https://api.hypothetical.com/offices/"
}
Tôi glossing qua một số chi tiết như accept
và content-type
, nhưng chúng ta hãy giả sử rằng API giả thuyết này hỗ trợ nội dung đàm phán và sự tốt lành khác của RESTful.
Giờ đây SPA sẽ hiển thị giao diện người dùng hiển thị hai mối quan hệ liên kết này với người dùng và người dùng có thể nhấp vào nút "Nhân viên" để xem nhân viên hoặc "Văn phòng". Giả sử người dùng nhấp vào "Nhân viên". SPA cần phải pushState()
một số href mới, nếu không quyết định điều hướng này sẽ không xuất hiện trong lịch sử và người dùng sẽ không thể sử dụng nút Quay lại để quay lại màn hình đầu tiên.
Điều này trình bày một tình trạng khó xử nhỏ: SPA nên sử dụng loại nào? Rõ ràng, nó không thể đẩy https://api.hypothetical.com/employees/
. Không chỉ là không phải là một tài nguyên hợp lệ trong SPA, nó không phải ngay cả trong cùng một nguồn gốc và pushState()
ném ngoại lệ nếu href mới có nguồn gốc khác.
Sự tiến thoái lưỡng nan là [có thể] dễ dàng giải quyết: SPA nhận thức được mối quan hệ liên kết được gọi là employees
, vì vậy SPA có thể mã hóa một URL cho tài nguyên này: pushState(...,'https://www.hypothetical.com/employees')
. Tiếp theo, nó sử dụng mối quan hệ liên kết https://api.hypothetical.com/employees/
để tìm nạp bộ sưu tập của nhân viên. API trả lại kết quả như sau:
{
"employees": [
{
"name": "John Doe",
"url": "https://api.hypothetical.com/employees/123",
},
{
"name": "Jane Doe",
"url": "https://api.hypothetical.com/employees/234",
},
...
]
}
Có hơn hai kết quả, nhưng tôi viết tắt bằng dấu ba chấm.
SPA muốn hiển thị dữ liệu này trong bảng nơi mỗi tên nhân viên là siêu liên kết để người dùng có thể xem thêm chi tiết về một nhân viên cụ thể. Người dùng nhấp vào "John Doe". SPA bây giờ cần hiển thị chi tiết về John Doe. Nó có thể dễ dàng có được các nguồn lực sử dụng các mối quan hệ liên kết, và nó có thể nhận được một cái gì đó như thế này:
{
"name": "John Doe",
"phone_number": "2025551234",
"office": {
"location": "Washington, DC",
"url": "https://api.hypothetical.com/offices/1"
},
"supervisor": {
"name": "Jane Doe",
"url": "https://api.hypothetical.com/employees/234"
},
"url": "https://api.hypothetical.com/employees/123"
}
Nhưng bây giờ tiến thoái lưỡng nan cùng tăng một lần nữa: những gì URL SPA nên chọn để đại diện cho nhà nước nội bộ mới này? Đây là tình trạng khó xử tương tự như trên, ngoại trừ thời gian này không thể mã hóa một URL SPA duy nhất, bởi vì có một số lượng nhân viên tùy ý.
Tôi nghĩ đây là một câu hỏi không tầm thường, nhưng hãy làm điều gì đó hacky để chúng tôi có thể tiếp tục tiến lên: SPA xây dựng một URL bằng cách thay thế 'api' trong tên máy chủ bằng 'www'.Đó là xấu xí khủng khiếp, nhưng nó không vi phạm HATEOAS (URL SPA chỉ được sử dụng phía khách hàng) và bây giờ SPA có thể pushState(...,'https://www.hypothetical.com/employees/123'
. Nói chung cách tiếp cận này, SPA có thể hiển thị các tùy chọn điều hướng cho bất kỳ mối quan hệ liên kết nào và người dùng có thể khám phá các tài nguyên liên quan: văn phòng của người này ở đâu? Số điện thoại của người giám sát là gì?
Điều này vẫn không giải quyết được liên kết sâu. Điều gì sẽ xảy ra nếu dấu trang của người dùng https://www.hypothetical.com/employees/123
, đóng trình duyệt và sau đó truy cập lại dấu trang này sau? Bây giờ SPA không có hồi ức về nguồn tài nguyên API cơ bản. Chúng tôi không thể đảo ngược sự thay thế (ví dụ: thay thế 'www' bằng 'api') bởi vì đó không phải là HATEOAS.
Các HATEOAS suy nghĩ dường như là các SPA nên yêu cầu https://api.hypothetical.com/
một lần nữa và theo các liên kết trở lại vào hồ sơ nhân viên John Doe, nhưng không có mối quan hệ liên kết cố định để có được từ employees
như một bộ sưu tập để John Doe
như một nhân viên cụ thể, vì vậy won mà 't làm việc.
Một cách tiếp cận HATEOAS khác là ứng dụng có thể đánh dấu các URL mà nó đã phát hiện ra. Ví dụ, nó có thể lưu trữ một bảng băm mà trước đây các bản đồ về thấy URL SPA để URL API:
{
"https://www.hypothetical.com/employees/123": "https://api.hypothetical.com/employees/123"
}
này sẽ cho phép các SPA để tìm thấy tài nguyên cơ bản và đưa ra giao diện người dùng, nhưng nó đòi hỏi nhà nước kiên trì xuyên suốt các phiên. Ví dụ. nếu chúng tôi lưu trữ băm này trong bộ nhớ HTML5 và người dùng xóa bộ nhớ HTML5 của họ thì tất cả dấu trang sẽ bị hỏng. Hoặc nếu người dùng gửi dấu trang này cho người dùng khác, người dùng khác sẽ không có ánh xạ URL SPA này đến URL API.
Điểm mấu chốt: triển khai SPA liên kết sâu bên trên API HATEOAS cảm thấy rất khó xử với tôi. Trong dự án hiện tại của tôi, tôi đã sử dụng SPA để xây dựng hầu như tất cả các URL. Do hậu quả của quyết định đó, API phải gửi số nhận dạng duy nhất (không chỉ URL) cho các tài nguyên cá nhân để SPA có thể tạo URL tốt cho chúng.
Có ai có kinh nghiệm làm việc này không? Có cách nào để đáp ứng các tiêu chí có vẻ mâu thuẫn này không?
nếu bạn có những trang khác nhau cho các nguồn tài nguyên khác nhau, nó không còn là SPA – gyoder