2015-03-13 22 views
5

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ư acceptcontent-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?

Trả lời

1

Tôi có thể thiếu một số thứ, nhưng có lẽ là do các loại tài nguyên khác nhau mà bạn có các chế độ xem/trang khác nhau. Vì vậy, khi bạn nạp nhân viên nó sử dụng giao diện employees.html và khi bạn nhận được để một nhân viên bạn sử dụng employee.html view..so tại sao woudl nó có nhiều như vậy

//user clicks employees 
pushState("employees.html#https://api.hypothetical.com/employees/") 

//user clicks on an employeed 
pushState("employee.html#https://api.hypothetical.com/employees/12345/") 

tôi có nghĩa là URI phần encode url chắc chắn ... nhưng bây giờ bạn có liên kết sâu đến các tài nguyên, không cần hack.

Tôi thấy pushState nhưng thực sự nó có thể chính xác hơn là pushViewState

+1

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

4

Tôi cũng phải vật lộn với khái niệm này. Một api ghét là tất cả về tách khách hàng khỏi máy chủ, vì vậy tôi nghĩ rằng hardcoding một bản đồ của "khách hàng url -> api uri" vào lưu trữ địa phương là một bước lùi vì những lý do bạn đề cập và nhiều hơn nữa. Điều đó đang được nói, không có gì liên quan đến việc có các ngôn ngữ miền riêng biệt cho máy khách và máy chủ. Bạn có thể có một số hành động nhất định trên trang (chẳng hạn như nhấp vào nhân viên # _) kích hoạt trạng thái đẩy với bất kỳ thứ gì bạn thích, có lẽ '/ employees/#'. Khi ứng dụng được khởi động vào trình duyệt khác bằng cách chia sẻ liên kết, một số dịch vụ sẽ biết cách đọc DSL '/ employees/#' và tua nhanh ứng dụng của bạn vào trạng thái thích hợp. Trong trường hợp quyền truy cập khác nhau, bạn có một số thông báo giải thích lý do tại sao bạn không thể truy cập vào nhân viên # _ và thay vào đó hãy liệt kê các nhân viên mà bạn có quyền xem. Nó có thể nhận được khá cồng kềnh nếu bạn có rất nhiều quan điểm liên kết sâu như thế này, nhưng đó là giá đại diện cho một đối tượng nhà nước phức tạp với một hệ thống phân cấp url phẳng.

Một cách tiếp cận khác mà tôi đã xem xét là nút "chia sẻ điều này" rõ ràng. Nhấp vào nút sẽ yêu cầu máy chủ đúc một url trong chính DSL của nó, để khi người dùng khác truy cập vào url chia sẻ này, máy chủ có thể chuyển thông tin trạng thái có liên quan cho khách hàng. Khách hàng phải được thiết lập để xử lý tình huống này, có lẽ với một số điều kiện xung quanh "nếu khu vực này chứa một 'liên kết sâu' bất động sản, làm điều gì đó đặc biệt.

Dù bằng cách nào đó không phải là một vấn đề dễ dàng để giải quyết.

+0

Gần hai năm sau: bất kỳ suy nghĩ mới nào về điều này? Tôi là một người mới đến REST và đang gặp vấn đề tương tự này, nơi nó dễ dàng xây dựng một khách hàng theo các liên kết sâu hơn một API máy chủ, nhưng một liên kết sâu trên máy khách có vẻ như nó sẽ * có * để biết về lược đồ URL của máy chủ, hoặc sẽ phải có một loại dịch vụ "cache liên kết sâu" thứ 3 chỉ để giải quyết vấn đề này ... –

Các vấn đề liên quan