# @codingame/json-rpc-2\.0 中文文档

规范地址：https://npmcn.com/package/%40codingame/json-rpc-2.0/

版本：1\.7\.0-next\.1
npm 元数据更新时间：2025-07-15T14:00:00.778Z
中文译文更新时间：2026-11-10T08:55:19.174Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40codingame/json-rpc-2.0
原文对照：https://npmcn.com/package/%40codingame/json-rpc-2.0/?lang=original
项目主页：https://github.com/shogowada/json-rpc-2.0#readme
源码仓库：https://github.com/shogowada/json-rpc-2.0

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：91.9 kB，27 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- 首次发布：2024-11-27T11:25:56.253Z
- 最新版本发布：2024-11-27T11:25:56.558Z
- 近 30 天下载量：2794（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：1（近 12 个月 0 个）

## 中文简介

JSON-RPC 2.0 客户端和服务器

## 安装

```sh
npm install @codingame/json-rpc-2.0
```

也可以使用：`pnpm add @codingame/json-rpc-2.0`、`yarn add @codingame/json-rpc-2.0`、`bun add @codingame/json-rpc-2.0`

## README

# json - rpc - 2.0 (韩语)

让您的客户端和服务器在函数调用下聊天 [JSON- RPC 2. 0 spec](https://www.jsonrpc.org/specification)。 。 。 .

-   协议不可知
    -   使用 HTTP, WebSocket, TCP, UDP, 进程间, 任意
        -   例如,从HTTP到WebSocket的简单迁移
-   无外部依赖关系
    -   保持您的包装小
    -   远离依赖地狱
-   在浏览器和节点中工作
-   第一等类型脚本支持
    -   在类型脚本中写入
    -   [强烈输入客户端和服务器呼叫](https://npmcn.com/package/%40codingame/json-rpc-2.0/#readme-typed-client-and-server)

## 安装

`npm install --save json-rpc-2.0`

## 示例

例子使用HTTP进行通信协议,但可以是任何东西.

### 服务器

```javascript
const express = require("express");
const bodyParser = require("body-parser");
const { JSONRPCServer } = require("json-rpc-2.0");

const server = new JSONRPCServer();

// First parameter is a method name.
// Second parameter is a method itself.
// A method takes JSON-RPC params and returns a result.
// It can also return a promise of the result.
server.addMethod("echo", ({ text }) => text);
server.addMethod("log", ({ message }) => console.log(message));

const app = express();
app.use(bodyParser.json());

app.post("/json-rpc", (req, res) => {
  const jsonRPCRequest = req.body;
  // server.receive takes a JSON-RPC request and returns a promise of a JSON-RPC response.
  // It can also receive an array of requests, in which case it may return an array of responses.
  // Alternatively, you can use server.receiveJSON, which takes JSON string as is (in this case req.body).
  server.receive(jsonRPCRequest).then((jsonRPCResponse) => {
    if (jsonRPCResponse) {
      res.json(jsonRPCResponse);
    } else {
      // If response is absent, it was a JSON-RPC notification method.
      // Respond with no content status (204).
      res.sendStatus(204);
    }
  });
});

app.listen(80);
```

#### 有认证

要将认证钩入 API,请输入自定义参数 :

```javascript
const server = new JSONRPCServer();

// The method can also take a custom parameter as the second parameter.
// Use this to inject whatever information that method needs outside the regular JSON-RPC request.
server.addMethod("echo", ({ text }, { userID }) => `${userID} said ${text}`);

app.post("/json-rpc", (req, res) => {
  const jsonRPCRequest = req.body;
  const userID = getUserID(req);

  // server.receive takes an optional second parameter.
  // The parameter will be injected to the JSON-RPC method as the second parameter.
  server.receive(jsonRPCRequest, { userID }).then((jsonRPCResponse) => {
    if (jsonRPCResponse) {
      res.json(jsonRPCResponse);
    } else {
      res.sendStatus(204);
    }
  });
});

const getUserID = (req) => {
  // Do whatever to get user ID out of the request
};
```

#### 中间软件

使用中间软件拦截请求和响应 :

```javascript
const server = new JSONRPCServer();

// next will call the next middleware
const logMiddleware = (next, request, serverParams) => {
  console.log(`Received ${JSON.stringify(request)}`);
  return next(request, serverParams).then((response) => {
    console.log(`Responding ${JSON.stringify(response)}`);
    return response;
  });
};

const exceptionMiddleware = async (next, request, serverParams) => {
  try {
    return await next(request, serverParams);
  } catch (error) {
    if (error.code) {
      return createJSONRPCErrorResponse(request.id, error.code, error.message);
    } else {
      throw error;
    }
  }
};

// Middleware will be called in the same order they are applied
server.applyMiddleware(logMiddleware, exceptionMiddleware);
```

#### 构造选项

选择时,可以将选项传递给 `JSONRPCServer` 构造器 :

```typescript
new JSONRPCServer({
  errorListener: (message: string, data: unknown): void => {
    // Listen to error here. By default, it will use console.warn to log errors.
  },
});
```

### 客户端

```javascript
import { JSONRPCClient } from "json-rpc-2.0";

// JSONRPCClient needs to know how to send a JSON-RPC request.
// Tell it by passing a function to its constructor. The function must take a JSON-RPC request and send it.
const client = new JSONRPCClient((jsonRPCRequest) =>
  fetch("http://localhost/json-rpc", {
    method: "POST",
    headers: {
      "content-type": "application/json",
    },
    body: JSON.stringify(jsonRPCRequest),
  }).then((response) => {
    if (response.status === 200) {
      // Use client.receive when you received a JSON-RPC response.
      return response
        .json()
        .then((jsonRPCResponse) => client.receive(jsonRPCResponse));
    } else if (jsonRPCRequest.id !== undefined) {
      return Promise.reject(new Error(response.statusText));
    }
  })
);

// Use client.request to make a JSON-RPC request call.
// The function returns a promise of the result.
client
  .request("echo", { text: "Hello, World!" })
  .then((result) => console.log(result));

// Use client.notify to make a JSON-RPC notification call.
// By definition, JSON-RPC notification does not respond.
client.notify("log", { message: "Hello, World!" });
```

#### 有认证

碞钩 `JSONRPCServer`,您可以向 `JSONRPCClient` 还有:

```javascript
const client = new JSONRPCClient(
  // It can also take a custom parameter as the second parameter.
  (jsonRPCRequest, { token }) =>
    fetch("http://localhost/json-rpc", {
      method: "POST",
      headers: {
        "content-type": "application/json",
        authorization: `Bearer ${token}`, // Use the passed token
      },
      body: JSON.stringify(jsonRPCRequest),
    }).then((response) => {
      // ...
    })
);

// Pass the custom params as the third argument.
client.request("echo", { text: "Hello, World!" }, { token: "foo's token" });
client.notify("log", { message: "Hello, World!" }, { token: "foo's token" });
```

#### 超时

有时你不愿无限期地等待回应. 你用得着 `timeout` 在某些延迟后自动失败请求:

```typescript
const client = new JSONRPCClient(/* ... */);

client
  .timeout(10 * 1000) // Automatically fails if it didn't get a response within 10 sec
  .request("echo", { text: "Hello, World!" });

// Create a custom error response
const createTimeoutJSONRPCErrorResponse = (
  id: JSONRPCID
): JSONRPCErrorResponse =>
  createJSONRPCErrorResponse(id, 123, "Custom error message");

client
  .timeout(10 * 1000, createTimeoutJSONRPCErrorResponse)
  .request("echo", { text: "Hello, World!" });
```

### 双向 JSON-RPC

双向JSON-RPC,使用 `JSONRPCServerAndClient`。 。 。 .

```javascript
const webSocket = new WebSocket("ws://localhost");

const serverAndClient = new JSONRPCServerAndClient(
  new JSONRPCServer(),
  new JSONRPCClient((request) => {
    try {
      webSocket.send(JSON.stringify(request));
      return Promise.resolve();
    } catch (error) {
      return Promise.reject(error);
    }
  })
);

webSocket.onmessage = (event) => {
  serverAndClient.receiveAndSend(JSON.parse(event.data.toString()));
};

// On close, make sure to reject all the pending requests to prevent hanging.
webSocket.onclose = (event) => {
  serverAndClient.rejectAllPendingRequests(
    `Connection is closed (${event.reason}).`
  );
};

serverAndClient.addMethod("echo", ({ text }) => text);

serverAndClient
  .request("add", { x: 1, y: 2 })
  .then((result) => console.log(`1 + 2 = ${result}`));
```

#### 构造选项

选择时,可以将选项传递给 `JSONRPCServerAndClient` 构造器 :

```typescript
new JSONRPCServerAndClient(server, client, {
  errorListener: (message: string, data: unknown): void => {
    // Listen to error here. By default, it will use console.warn to log errors.
  },
});
```

### 处理错误

回答错误时,用 `Error`在客户一方,承诺将被拒绝 `Error` 对象为同一信件.

```javascript
server.addMethod("fail", () =>
  Promise.reject(new Error("This is an error message."))
);

client.request("fail").then(
  () => console.log("This does not get called"),
  (error) => console.error(error.message) // Outputs "This is an error message."
);
```

如果您想要返回自定义错误响应, 请使用 `JSONRPCErrorException`数字 :

```typescript
import { JSONRPCErrorException } from "json-rpc-2.0";

const server = new JSONRPCServer();

server.addMethod("throws", () => {
  const errorCode = 123;
  const errorData = {
    foo: "bar",
  };

  throw new JSONRPCErrorException(
    "A human readable error message",
    errorCode,
    errorData
  );
});
```

或者,使用 [高级 API](https://npmcn.com/package/%40codingame/json-rpc-2.0/#readme-advanced-apis) 或执行 `mapErrorToJSONRPCErrorResponse`数字 :

```typescript
import {
  createJSONRPCErrorResponse,
  JSONRPCErrorResponse,
  JSONRPCID,
  JSONRPCServer,
} from "json-rpc-2.0";

const server = new JSONRPCServer();

server.mapErrorToJSONRPCErrorResponse = (
  id: JSONRPCID,
  error: any
): JSONRPCErrorResponse => {
  return createJSONRPCErrorResponse(
    id,
    error?.code || 0,
    error?.message || "An unexpected error occurred",
    // Optional 4th argument. It maps to error.data of the response.
    { foo: "bar" }
  );
};
```

### 高级 API

使用高级API处理原始JSON-RPC消息.

#### 服务器

```typescript
import { JSONRPC, JSONRPCResponse, JSONRPCServer } from "json-rpc-2.0";

const server = new JSONRPCServer();

// Advanced method takes a raw JSON-RPC request and returns a raw JSON-RPC response
server.addMethodAdvanced(
  "doSomething",
  (jsonRPCRequest: JSONRPCRequest): PromiseLike<JSONRPCResponse> => {
    if (isValid(jsonRPCRequest.params)) {
      return {
        jsonrpc: JSONRPC,
        id: jsonRPCRequest.id,
        result: "Params are valid",
      };
    } else {
      return {
        jsonrpc: JSONRPC,
        id: jsonRPCRequest.id,
        error: {
          code: -100,
          message: "Params are invalid",
          data: jsonRPCRequest.params,
        },
      };
    }
  }
);
```

```typescript
// You can remove the added method if needed
server.removeMethod("doSomething");
```

#### 客户端

```typescript
import {
  JSONRPC,
  JSONRPCClient,
  JSONRPCRequest,
  JSONRPCResponse,
} from "json-rpc-2.0";

const send = () => {
  // ...
};
let nextID: number = 0;
const createID = () => nextID++;

// To avoid conflict ID between basic and advanced method request, inject a custom ID factory function.
const client = new JSONRPCClient(send, createID);

const jsonRPCRequest: JSONRPCRequest = {
  jsonrpc: JSONRPC,
  id: createID(),
  method: "doSomething",
  params: {
    foo: "foo",
    bar: "bar",
  },
};

// Advanced method takes a raw JSON-RPC request and returns a raw JSON-RPC response
// It can also send an array of requests, in which case it returns an array of responses.
client
  .requestAdvanced(jsonRPCRequest)
  .then((jsonRPCResponse: JSONRPCResponse) => {
    if (jsonRPCResponse.error) {
      console.log(
        `Received an error with code ${jsonRPCResponse.error.code} and message ${jsonRPCResponse.error.message}`
      );
    } else {
      doSomethingWithResult(jsonRPCResponse.result);
    }
  });
```

### 输入客户端和服务器

强打字 `request` 财务报告和审定财务报表 `addMethod` 方法、用途 `TypedJSONRPCClient`, (中文(简体) ), `TypedJSONRPCServer` 财务报告和审定财务报表 `TypedJSONRPCServerAndClient` 接口.

```typescript
import {
  JSONRPCClient,
  JSONRPCServer,
  JSONRPCServerAndClient,
  TypedJSONRPCClient,
  TypedJSONRPCServer,
  TypedJSONRPCServerAndClient,
} from "json-rpc-2.0";

// Use `type` instead of `interface`. In TypeScript, interface can be exnteded,
// so the type checker considers the possibility of the interface being extended,
// resulting in an error.
// Reference: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces
type Methods = {
  echo(params: { message: string }): string;
  sum(params: { x: number; y: number }): number;
};

const server: TypedJSONRPCServer<Methods> = new JSONRPCServer(/* ... */);
const client: TypedJSONRPCClient<Methods> = new JSONRPCClient(/* ... */);

// Types are infered from the Methods type
server.addMethod("echo", ({ message }) => message);
server.addMethod("sum", ({ x, y }) => x + y);
// These result in type error
// server.addMethod("ech0", ({ message }) => message); // typo in method name
// server.addMethod("echo", ({ messagE }) => messagE); // typo in param name
// server.addMethod("echo", ({ message }) => 123); // return type must be string

client
  .request("echo", { message: "hello" })
  .then((result) => console.log(result));
client.request("sum", { x: 1, y: 2 }).then((result) => console.log(result));
// These result in type error
// client.request("ech0", { message: "hello" }); // typo in method name
// client.request("echo", { messagE: "hello" }); // typo in param name
// client.request("echo", { message: 123 }); // message param must be string
// client
//   .request("echo", { message: "hello" })
//   .then((result: number) => console.log(result)); // return type must be string

// The same rule applies to TypedJSONRPCServerAndClient
type ServerAMethods = {
  echo(params: { message: string }): string;
};

type ServerBMethods = {
  sum(params: { x: number; y: number }): number;
};

const serverAndClientA: TypedJSONRPCServerAndClient<
  ServerAMethods,
  ServerBMethods
> = new JSONRPCServerAndClient(/* ... */);
const serverAndClientB: TypedJSONRPCServerAndClient<
  ServerBMethods,
  ServerAMethods
> = new JSONRPCServerAndClient(/* ... */);

serverAndClientA.addMethod("echo", ({ message }) => message);
serverAndClientB.addMethod("sum", ({ x, y }) => x + y);

serverAndClientA
  .request("sum", { x: 1, y: 2 })
  .then((result) => console.log(result));
serverAndClientB
  .request("echo", { message: "hello" })
  .then((result) => console.log(result));
```

## 构建

`npm run build`

## 测试

`npm test`

## 常见问题

### @codingame/json-rpc-2\.0 是什么？

JSON-RPC 2\.0 客户端和服务器

### 如何安装 @codingame/json-rpc-2\.0？

在项目目录运行 npm install @codingame/json-rpc-2\.0，或使用 pnpm add / yarn add / bun add。

### @codingame/json-rpc-2\.0 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @codingame/json-rpc-2\.0 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @codingame/json-rpc-2\.0 可以商用吗？

@codingame/json-rpc-2\.0 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @codingame/json-rpc-2\.0 的下载量有多少？

根据 npm 官方下载统计，@codingame/json-rpc-2\.0 在 2026/10/10 – 2026/11/08 这 30 天内被下载 2,794 次，日均约 93 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @codingame/json-rpc-2\.0 还在维护吗？

最新版本 1\.7\.0-next\.1 发布于 2024/11/27（1\.9 年前）；至今共发布 1 个版本，其中过去 12 个月发布了 0 个；首次发布于 2024/11/27。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

