6 điểm bởi GN⁺ 2025-09-23 | Chưa có bình luận nào. | Chia sẻ qua WhatsApp
  • Cap'n Webgiao thức RPC mới được triển khai bằng TypeScript, được tối ưu cho môi trường web và hoạt động trên nhiều runtime JavaScript khác nhau
  • Không cần schema hay boilerplate rườm rà, cung cấp tuần tự hóa dựa trên JSONđịnh dạng dữ liệu con người có thể đọc được
  • Thông qua mô hình dựa trên object-capability, nó hỗ trợ gọi hai chiều, truyền tham chiếu hàm và đối tượng, promise pipelining, và triển khai các mẫu bảo mật
  • Hỗ trợ nhiều môi trường mạng như WebSocket, HTTP, postMessage, đồng thời là mã nguồn mở nhẹ dưới 10kB
  • Không chỉ giải quyết vấn đề waterfall tương tự GraphQL, mà còn cho phép mô hình hóa RPC tự nhiên như API JavaScript thông thường

Cap'n Web là gì

  • Cap'n Webhệ thống RPC (protocol) mã nguồn mở dựa trên TypeScript do Cloudflare phát triển
  • Lấy cảm hứng từ Cap'n Proto, nhưng hoạt động không cần định nghĩa schema riêng, và áp dụng cách tuần tự hóa thân thiện với con người bằng JSON
  • Tích hợp với TypeScript để cải thiện trải nghiệm lập trình viên như tự động hoàn thành và kiểm tra kiểu; việc xác thực kiểu ở runtime có thể xử lý riêng (như type guard)
  • Hỗ trợ các giao thức mạng như HTTP, WebSocket, postMessage và chạy trên các trình duyệt chính, Cloudflare Workers, Node.js
  • Cấu trúc nhẹ không phụ thuộc thư viện, có kích thước dưới 10kB sau khi minify + gzip

Mô hình object-capability (OCap) của Cap'n Web

  • Áp dụng mô hình dựa trên object-capability, cho phép biểu đạt phong phú hơn các hệ thống RPC hiện có
    • Gọi hai chiều: client và server có thể gọi hàm của nhau
    • Truyền tham chiếu hàm và đối tượng: khi truyền hàm hoặc đối tượng qua RPC, phía nhận sẽ nhận stub và khi gọi thì thực thi tại vị trí gốc
    • Promise Pipelining: khi nối chuỗi nhiều RPC, có thể xử lý chỉ với một lần round trip mạng
    • Mẫu bảo mật: có thể triển khai tự nhiên các cơ chế kiểm soát bảo mật như cấp quyền và quản lý phiên

Cách sử dụng cơ bản

  • Ví dụ phía client

    import { newWebSocketRpcSession } from "capnweb"  
    let api = newWebSocketRpcSession("wss://example.com/api")  
    let result = await api.hello("World")  
    console.log(result)  
    
  • Ví dụ phía server (dựa trên Cloudflare Worker)

    import { RpcTarget, newWorkersRpcResponse } from "capnweb"  
    class MyApiServer extends RpcTarget {  
      hello(name) {  
        return `Hello, ${name}!`  
      }  
    }  
    export default {  
      fetch(request, env, ctx) {  
        let url = new URL(request.url)  
        if (url.pathname === "/api") {  
          return newWorkersRpcResponse(request, new MyApiServer())  
        }  
        return new Response("Not found", {status: 404})  
      }  
    }  
    
  • Có thể dễ dàng thêm method vào API, truyền callback từ client, cũng như định nghĩa và áp dụng interface TypeScript

RPC là gì và đặc điểm trong Cap'n Web

  • RPC (Remote Procedure Call) là khái niệm cho phép hai chương trình trên mạng giao tiếp như thể đang gọi hàm
  • Khác với giao thức HTTP/REST truyền thống, RPC cung cấp lớp trừu tượng gọi hàm, cho phép viết mã phù hợp với cách tư duy của lập trình viên
  • Cap'n Web phù hợp với luồng JavaScript hiện đại nhờ hỗ trợ async/await, Promise, Exception
  • Không giống những tranh cãi lịch sử về RPC (gọi đồng bộ, lỗi mạng), trong môi trường JS hiện đại nó có thể được dùng an toàn và hiệu quả hơn

Các kịch bản sử dụng Cap'n Web

  • Phù hợp với mọi môi trường cần giao tiếp mạng giữa hai ứng dụng JavaScript
    • Gọi giữa client-server, giữa các microservice, v.v.
    • Đặc biệt phù hợp với web app cộng tác thời gian thực và các tương tác vượt qua ranh giới bảo mật phức tạp
  • Vẫn đang ở giai đoạn thử nghiệm, nên càng hữu ích hơn với các nhà phát triển cởi mở với công nghệ mới

Nhiều tính năng khác nhau

Chế độ batch HTTP

  • Khi không cần kết nối liên tục, có thể dùng chế độ batch HTTP để gộp nhiều lệnh gọi RPC và xử lý cùng lúc

    import { newHttpBatchRpcSession } from "capnweb"  
    let batch = newHttpBatchRpcSession("https://example.com/api";)  
    let result = await batch.hello("World")  
    console.log(result)  
    
  • Có thể thực thi đồng thời nhiều lời gọi trong cùng một batch và nhận kết quả song song

    let promise1 = batch.hello("Alice")  
    let promise2 = batch.hello("Bob")  
    let [result1, result2] = await Promise.all([promise1, promise2])  
    

Promise Pipelining (gọi chuỗi)

  • Hỗ trợ cách dùng ngay kết quả làm đối số cho lệnh gọi tiếp theo mà không cần chờ lệnh gọi trước hoàn tất

  • Ví dụ: truyền trực tiếp Promise kết quả của getMyName() vào hello() để xử lý chỉ với một lần round trip mạng

    let namePromise = batch.getMyName()  
    let result = await batch.hello(namePromise)  
    
  • Promise của Cap'n Web hoạt động như đối tượng proxy, cho phép nối thêm method mà không bị trì hoãn

    let sessionPromise = batch.authenticate(apiKey)  
    let name = await sessionPromise.whoami()  
    

Bảo mật: xác thực và object-capability

  • Thông qua method authenticate, hệ thống cấp đối tượng quyền hạn (session) khi thành công, sau đó có thể gọi chức năng mà không cần thêm bước xác thực
  • Khác với RPC truyền thống, không thể giả mạo đối tượng session, và cũng không thể truy cập method yêu cầu quyền nếu chưa xác thực
  • Tự nhiên khắc phục các giới hạn cấu trúc của WebSocket, đồng thời bảo đảm tính nhất quán của logic xác thực
  • Khi khai báo interface API bằng TypeScript, có thể tự động áp dụng từ client đến server, đồng thời bảo đảm tự động hoàn thành và độ an toàn kiểu

So sánh với GraphQL và điểm khác biệt của Cap'n Web

  • GraphQL làm giảm vấn đề waterfall nhiều tầng của REST, nhưng đòi hỏi đưa vào ngôn ngữ, schema và toolchain mới

  • Cap'n Web giải quyết vấn đề waterfall chỉ bằng mã JavaScript, đồng thời

    • nhờ hỗ trợ promise pipelining/tham chiếu đối tượng, có thể mô hình hóa tự nhiên các lời gọi lồng nhau hoặc logic giao dịch phức hợp
    let user = api.createUser({ name: "Alice" })  
    let friendRequest = await user.sendFriendRequest("Bob")  
    
  • Có thể sử dụng giống API JavaScript mà không cần gánh độ phức tạp và chi phí học tập/quản lý của GraphQL

Phép toán mảng (array.map v.v.) và tối ưu hóa

  • Trong Cap'n Web, có thể thực hiện phép map trên từng phần tử mảng mà không phát sinh thêm round trip mạng

  • Hàm callback của map được chạy một lần ở client để ghi lại nội dung tính toán (record-replay), sau đó gửi lên server để xử lý hàng loạt phía server

    let friendsWithPhotos = friendsPromise.map(friend => {  
      return {friend, photo: api.getUserPhoto(friend.id)}  
    })  
    let results = await friendsWithPhotos  
    
  • Thông qua một DSL chuyên biệt trong phạm vi giới hạn, nó cho phép biểu đạt như hàm JavaScript, nhưng thực tế dùng giao thức Cap'n Web để tối ưu nhiều lời gọi

Cấu trúc giao thức nội bộ và luồng giao tiếp

  • Truyền dữ liệu có cấu trúc thông qua JSON + tiền xử lý đặc biệt, hỗ trợ các kiểu đặc biệt như mảng, ngày tháng
  • Giao thức đối xứng cho phép giao tiếp hai chiều không phân biệt client và server
  • Mỗi bên (ví dụ: Alice và Bob) quản lý bảng export/import, và phân biệt tham chiếu đối tượng/hàm bằng ID
  • Thông qua các thông điệp push/pull và việc cấp phát Promise ID, có thể phản ánh nhiều lời gọi trong một round trip

Tình hình hiện tại và các trường hợp áp dụng

  • Cap'n Web hiện vẫn là mã nguồn mở mang tính thử nghiệm, nhưng đã được dùng trong dịch vụ thực tế như remote bindings của Cloudflare Wrangler
  • Dự kiến sẽ có thêm các bài blog và nhiều thử nghiệm frontend khác
  • Được phát hành theo giấy phép MIT, bất kỳ ai cũng có thể tự do áp dụng
  • Đi tới kho GitHub

Chưa có bình luận nào.

Chưa có bình luận nào.