基础协议

基础协议由标头和内容组成。标头和内容之间使用 \r\n 分隔。

标头

标头由标头字段组成。每个标头字段包含一个名称和值,用 : (冒号和空格)分隔。标头字段的结构符合 HTTP 语义。每个标头字段都以 \r\n 结尾。考虑到每个标头字段和整个标头都以 \r\n 结尾,并且至少有一个标头字段,这意味着在内容之前始终都有两个 \r\n

目前支持的标头字段:

标头字段名值类型描述
Content-Lengthnumber内容部分以字节计算的长度,这个标头是必须的。
Content-Typestring内容部分的 MIME 类型。默认是 application/vscode-jsonrpc; charset=utf-8

标头部分使用 ascii 编码进行编码。这包括分隔标题和内容部分的 \r\n

内容

包含消息实际的内容。消息的内容部分使用 JSON-RPC 来描述请求响应通知。内容部分使用 Content-Type 字段中提供的字符集进行编码。它默认为 utf-8,这是目前唯一支持的编码。如果服务器客户端收到的标头编码与 utf-8 不同,则应响应错误。

该协议的早期版本使用字符串常量 utf8,根据规范,它不是正确的编码常量。为了向后兼容,强烈建议客户端和服务器将字符串 utf8 视为 utf-8

示例:

Content-Length: ...\r\n
\r\n
{
	"jsonrpc": "2.0",
	"id": 1,
	"method": "textDocument/completion",
	"params": {
		...
	}
}

基础协议 JSON 结构

以下 TypeScript 定义描述了基本 JSON-RPC 协议:

基础类型

该协议对整数、无符号整数、十进制数、对象和数组使用以下定义:

/**
 * Defines an integer number in the range of -2^31 to 2^31 - 1.
 */
export type integer = number;
/**
 * Defines an unsigned integer number in the range of 0 to 2^31 - 1.
 */
export type uinteger = number;
/**
 * Defines a decimal number. Since decimal numbers are very
 * rare in the language server specification we denote the
 * exact range with every decimal using the mathematics
 * interval notation (e.g. [0, 1] denotes all decimals d with
 * 0 <= d <= 1.
 */
export type decimal = number;
/**
 * The LSP any type
 *
 * @since 3.17.0
 */
export type LSPAny = LSPObject | LSPArray | string | integer | uinteger |
	decimal | boolean | null;
/**
 * LSP object definition.
 *
 * @since 3.17.0
 */
export type LSPObject = { [key: string]: LSPAny };
/**
 * LSP arrays.
 *
 * @since 3.17.0
 */
export type LSPArray = LSPAny[];

抽象消息

由 JSON-RPC 定义的常规消息。语言服务器协议始终使用 "2.0" 作为 jsonrpc 版本。

interface Message {
	jsonrpc: string;
}

请求消息

用于描述客户端和服务器之间的请求的请求消息(可以由客户端发出,也可以由服务端发出)。每个已处理的请求都必须将响应发送回请求的发送方。

interface RequestMessage extends Message {

	/**
	 * The request id.
	 */
	id: integer | string;

	/**
	 * The method to be invoked.
	 */
	method: string;

	/**
	 * The method's params.
	 */
	params?: array | object;
}

响应消息

响应消息作为请求的结果发送。如果请求未提供结果值,请求的接收方仍需要返回响应消息以符合 JSON-RPC 规范。在这种情况下,应将 ResponseMessageresult 属性设置为 null 以表示请求成功。

interface ResponseMessage extends Message {
	/**
	 * The request id.
	 */
	id: integer | string | null;

	/**
	 * The result of a request. This member is REQUIRED on success.
	 * This member MUST NOT exist if there was an error invoking the method.
	 */
	result?: string | number | boolean | array | object | null;

	/**
	 * The error object in case a request fails.
	 */
	error?: ResponseError;
}
interface ResponseError {
	/**
	 * A number indicating the error type that occurred.
	 */
	code: integer;

	/**
	 * A string providing a short description of the error.
	 */
	message: string;

	/**
	 * A primitive or structured value that contains additional
	 * information about the error. Can be omitted.
	 */
	data?: string | number | boolean | array | object | null;
}
export namespace ErrorCodes {
	// Defined by JSON-RPC
	export const ParseError: integer = -32700;
	export const InvalidRequest: integer = -32600;
	export const MethodNotFound: integer = -32601;
	export const InvalidParams: integer = -32602;
	export const InternalError: integer = -32603;

	/**
	 * This is the start range of JSON-RPC reserved error codes.
	 * It doesn't denote a real error code. No LSP error codes should
	 * be defined between the start and end range. For backwards
	 * compatibility the `ServerNotInitialized` and the `UnknownErrorCode`
	 * are left in the range.
	 *
	 * @since 3.16.0
	 */
	export const jsonrpcReservedErrorRangeStart: integer = -32099;
	/** @deprecated use jsonrpcReservedErrorRangeStart */
	export const serverErrorStart: integer = jsonrpcReservedErrorRangeStart;

	/**
	 * Error code indicating that a server received a notification or
	 * request before the server has received the `initialize` request.
	 */
	export const ServerNotInitialized: integer = -32002;
	export const UnknownErrorCode: integer = -32001;

	/**
	 * This is the end range of JSON-RPC reserved error codes.
	 * It doesn't denote a real error code.
	 *
	 * @since 3.16.0
	 */
	export const jsonrpcReservedErrorRangeEnd = -32000;
	/** @deprecated use jsonrpcReservedErrorRangeEnd */
	export const serverErrorEnd: integer = jsonrpcReservedErrorRangeEnd;

	/**
	 * This is the start range of LSP reserved error codes.
	 * It doesn't denote a real error code.
	 *
	 * @since 3.16.0
	 */
	export const lspReservedErrorRangeStart: integer = -32899;

	/**
	 * A request failed but it was syntactically correct, e.g the
	 * method name was known and the parameters were valid. The error
	 * message should contain human readable information about why
	 * the request failed.
	 *
	 * @since 3.17.0
	 */
	export const RequestFailed: integer = -32803;

	/**
	 * The server cancelled the request. This error code should
	 * only be used for requests that explicitly support being
	 * server cancellable.
	 *
	 * @since 3.17.0
	 */
	export const ServerCancelled: integer = -32802;

	/**
	 * The server detected that the content of a document got
	 * modified outside normal conditions. A server should
	 * NOT send this error code if it detects a content change
	 * in it unprocessed messages. The result even computed
	 * on an older state might still be useful for the client.
	 *
	 * If a client decides that a result is not of any use anymore
	 * the client should cancel the request.
	 */
	export const ContentModified: integer = -32801;

	/**
	 * The client has canceled a request and a server has detected
	 * the cancel.
	 */
	export const RequestCancelled: integer = -32800;

	/**
	 * This is the end range of LSP reserved error codes.
	 * It doesn't denote a real error code.
	 *
	 * @since 3.16.0
	 */
	export const lspReservedErrorRangeEnd: integer = -32800;
}

通知消息

通知消息。已处理的通知消息不得发回响应。它们像事件一样工作。

interface NotificationMessage extends Message {
	/**
	 * The method to be invoked.
	 */
	method: string;

	/**
	 * The notification's params.
	 */
	params?: array | object;
}

$通知和请求

方法以 $/ 开头的通知和请求是依赖于协议(由客户端和服务器自行约定)实现的消息,可能无法在所有客户端或服务器中实现。例如,如果服务器实现使用单线程同步编程语言,则服务器几乎无法对 $/cancelRequest 通知做出反应。如果服务器或客户端收到以 $/ 开头的通知,则可以忽略该通知。如果服务器或客户端收到以 $/ 开头的请求,则必须使用错误代码 MethodNotFound (例如 -32601)响应请求。

支持取消

基本协议支持取消请求。若要取消请求,将发送具有以下属性的通知消息:

NotificationMessage:

  • method: "$/cancelRequest"
  • params: CancelParams 定义如下:
interface CancelParams {
	/**
	 * The request id to cancel.
	 */
	id: integer | string;
}

已取消的请求仍需要从服务器返回并发送回响应。它不能保持打开/挂起。这符合 JSON-RPC 协议,该协议要求每个请求都发送回响应。此外,它还允许在取消时返回部分结果。如果请求在取消时返回错误响应,建议将错误代码设置为 ErrorCodes.RequestCancelled。

支持进度

Since version 3.15.0

基本协议还支持以通用方式报告进度。此机制可用于报告任何类型的进度,包括已完成的工作进度(通常用于使用进度条在用户界面中报告进度)和部分结果进度,以支持结果流式处理。

进度通知具有以下属性:

NotificationMessage:

  • method: "$/progress"
  • params: ProgressParams 定义如下:
interface ProgressParams<T> {
	/**
	 * The progress token provided by the client or server.
	 */
	token: ProgressToken;

	/**
	 * The progress data.
	 */
	value: T;
}
type ProgressToken = integer | string;

泛型 T 由协议约定

针对 token 报告进度。token 与请求 id 不同,它允许带外数据报告进度。