golang实现JSON-RPC 2.0协议的开发插件库jsonrpc的使用
Golang实现JSON-RPC 2.0协议的开发插件库jsonrpc的使用
关于
- 简单、优雅、简洁
- 符合JSON-RPC 2.0规范
安装
$ go get github.com/osamingo/jsonrpc/v2@latest
使用示例
基础示例
package main
import (
"context"
"log"
"net/http"
"github.com/goccy/go-json"
"github.com/osamingo/jsonrpc/v2"
)
type (
// EchoHandler 定义Echo方法处理器
EchoHandler struct{}
// EchoParams 定义Echo方法的参数结构
EchoParams struct {
Name string `json:"name"`
}
// EchoResult 定义Echo方法的返回结果结构
EchoResult struct {
Message string `json:"message"`
}
// PositionalHandler 定义Positional方法处理器
PositionalHandler struct{}
// PositionalParams 定义Positional方法的参数结构(位置参数)
PositionalParams []int
// PositionalResult 定义Positional方法的返回结果结构
PositionalResult struct {
Message []int `json:"message"`
}
)
// ServeJSONRPC 实现Echo方法的处理逻辑
func (h EchoHandler) ServeJSONRPC(c context.Context, params *json.RawMessage) (any, *jsonrpc.Error) {
var p EchoParams
if err := jsonrpc.Unmarshal(params, &p); err != nil {
return nil, err
}
return EchoResult{
Message: "Hello, " + p.Name,
}, nil
}
// ServeJSONRPC 实现Positional方法的处理逻辑
func (h PositionalHandler) ServeJSONRPC(c context.Context, params *json.RawMessage) (any, **jsonrpc.Error) {
var p PositionalParams
if err := jsonrpc.Unmarshal(params, &p); err != nil {
return nil, err
}
return PositionalResult{
Message: p,
}, nil
}
func main() {
// 创建方法仓库
mr := jsonrpc.NewMethodRepository()
// 注册Echo方法
if err := mr.RegisterMethod("Main.Echo", EchoHandler{}, EchoParams{}, EchoResult{}); err != nil {
log.Fatalln(err)
}
// 注册Positional方法
if err := mr.RegisterMethod("Main.Positional", PositionalHandler{}, PositionalParams{}, PositionalResult{}); err != nil {
log.Fatalln(err)
}
// 设置HTTP路由
http.Handle("/jrpc", mr)
http.HandleFunc("/jrpc/debug", mr.ServeDebug)
// 启动HTTP服务
if err := http.ListenAndServe(":8080", http.DefaultServeMux); err != nil {
log.Fatalln(err)
}
}
高级示例
package main
import (
"log"
"net/http"
"github.com/osamingo/jsonrpc/v2"
)
type (
// HandleParamsResulter 定义处理器接口
HandleParamsResulter interface {
jsonrpc.Handler
Name() string
Params() any
Result() any
}
// Servicer 定义服务接口
Servicer interface {
MethodName(HandleParamsResulter) string
Handlers() []HandleParamsResulter
}
// UserService 用户服务结构
UserService struct {
SignUpHandler HandleParamsResulter
SignInHandler HandleParamsResulter
}
)
// MethodName 实现服务接口的方法名生成
func (us *UserService) MethodName(h HandleParamsResulter) string {
return "UserService." + h.Name()
}
// Handlers 返回所有处理器
func (us *UserService) Handlers() []HandleParamsResulter {
return []HandleParamsResulter{us.SignUpHandler, us.SignInHandler}
}
// NewUserService 创建用户服务实例
func NewUserService() *UserService {
return &UserService{
// 初始化处理器
}
}
func main() {
// 创建方法仓库
mr := jsonrpc.NewMethodRepository()
// 注册服务方法
for _, s := range []Servicer{NewUserService()} {
for _, h := range s.Handlers() {
mr.RegisterMethod(s.MethodName(h), h, h.Params(), h.Result())
}
}
// 设置HTTP路由
http.Handle("/jrpc", mr)
http.HandleFunc("/jrpc/debug", mr.ServeDebug)
// 启动HTTP服务
if err := http.ListenAndServe(":8080", http.DefaultServeMux); err != nil {
log.Fatalln(err)
}
}
调用示例
调用Echo方法
请求:
{
"jsonrpc": "2.0",
"method": "Main.Echo",
"params": {
"name": "John Doe"
},
"id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b"
}
响应:
{
"jsonrpc": "2.0",
"result": {
"message": "Hello, John Doe"
},
"id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b"
}
调用Positional方法
请求:
{
"jsonrpc": "2.0",
"method": "Main.Positional",
"params": [3,1,1,3,5,3],
"id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b"
}
响应:
{
"jsonrpc": "2.0",
"result": {
"message": [3,1,1,3,5,3]
},
"id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b"
}
访问调试接口
响应:
[
{
"handler": "EchoHandler",
"name": "Main.Echo",
"params": {
"$ref": "#/definitions/EchoParams",
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"EchoParams": {
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
}
},
"result": {
"$ref": "#/definitions/EchoResult",
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"EchoResult": {
"additionalProperties": false,
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
],
"type": "object"
}
}
}
}
]
许可证
MIT许可证
更多关于golang实现JSON-RPC 2.0协议的开发插件库jsonrpc的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现JSON-RPC 2.0协议的开发插件库jsonrpc的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang实现JSON-RPC 2.0协议开发指南
JSON-RPC 2.0是一种轻量级的远程过程调用协议,使用JSON作为数据格式。在Golang中,标准库net/rpc/jsonrpc
提供了基本的JSON-RPC支持,但功能较为基础。下面我将介绍如何使用更强大的第三方库github.com/gorilla/rpc/v2/jsonrpc
来实现JSON-RPC 2.0服务。
安装依赖
首先安装必要的库:
go get github.com/gorilla/rpc/v2
go get github.com/gorilla/rpc/v2/jsonrpc
服务端实现
1. 定义服务方法
package main
import (
"errors"
"net/http"
"log"
"github.com/gorilla/rpc/v2"
"github.com/gorilla/rpc/v2/jsonrpc"
)
type Args struct {
A, B int
}
type Reply struct {
Result int
}
type ArithService struct{}
func (s *ArithService) Multiply(r *http.Request, args *Args, reply *Reply) error {
reply.Result = args.A * args.B
return nil
}
func (s *ArithService) Divide(r *http.Request, args *Args, reply *Reply) error {
if args.B == 0 {
return errors.New("divide by zero")
}
reply.Result = args.A / args.B
return nil
}
2. 创建并启动服务
func main() {
// 创建RPC服务
s := rpc.NewServer()
s.RegisterCodec(jsonrpc.NewCodec(), "application/json")
// 注册服务
arith := new(ArithService)
s.RegisterService(arith, "")
// 设置HTTP路由
http.Handle("/rpc", s)
// 启动HTTP服务
log.Println("Starting JSON-RPC server on localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
客户端实现
1. 创建客户端
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type Client struct {
url string
}
func NewClient(url string) *Client {
return &Client{url: url}
}
func (c *Client) Call(method string, args interface{}, reply interface{}) error {
// 构造请求体
request := map[string]interface{}{
"jsonrpc": "2.0",
"method": method,
"params": args,
"id": 1,
}
// 编码为JSON
body, err := json.Marshal(request)
if err != nil {
return err
}
// 发送HTTP请求
resp, err := http.Post(c.url, "application/json", bytes.NewBuffer(body))
if err != nil {
return err
}
defer resp.Body.Close()
// 读取响应
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
// 解析响应
var response struct {
Jsonrpc string `json:"jsonrpc"`
Result interface{} `json:"result"`
Error interface{} `json:"error"`
Id int `json:"id"`
}
if err := json.Unmarshal(data, &response); err != nil {
return err
}
// 处理错误
if response.Error != nil {
return fmt.Errorf("RPC error: %v", response.Error)
}
// 解码结果
resultBytes, err := json.Marshal(response.Result)
if err != nil {
return err
}
return json.Unmarshal(resultBytes, reply)
}
2. 使用客户端调用服务
func main() {
client := NewClient("http://localhost:8080/rpc")
// 乘法调用
var multiplyReply Reply
err := client.Call("ArithService.Multiply", &Args{A: 5, B: 6}, &multiplyReply)
if err != nil {
fmt.Println("Multiply error:", err)
} else {
fmt.Println("Multiply result:", multiplyReply.Result)
}
// 除法调用
var divideReply Reply
err = client.Call("ArithService.Divide", &Args{A: 10, B: 2}, ÷Reply)
if err != nil {
fmt.Println("Divide error:", err)
} else {
fmt.Println("Divide result:", divideReply.Result)
}
// 错误调用(除零)
err = client.Call("ArithService.Divide", &Args{A: 10, B: 0}, ÷Reply)
if err != nil {
fmt.Println("Divide error:", err)
} else {
fmt.Println("Divide result:", divideReply.Result)
}
}
高级特性
1. 批量请求支持
JSON-RPC 2.0支持批量请求,可以一次发送多个方法调用:
func (c *Client) BatchCall(requests []map[string]interface{}) ([]map[string]interface{}, error) {
body, err := json.Marshal(requests)
if err != nil {
return nil, err
}
resp, err := http.Post(c.url, "application/json", bytes.NewBuffer(body))
if err != nil {
return nil, err
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var responses []map[string]interface{}
if err := json.Unmarshal(data, &responses); err != nil {
return nil, err
}
return responses, nil
}
2. 通知(Notification)支持
JSON-RPC 2.0支持通知(没有返回值的调用):
func (c *Client) Notify(method string, args interface{}) error {
request := map[string]interface{}{
"jsonrpc": "2.0",
"method": method,
"params": args,
}
body, err := json.Marshal(request)
if err != nil {
return err
}
_, err = http.Post(c.url, "application/json", bytes.NewBuffer(body))
return err
}
错误处理
JSON-RPC 2.0定义了标准错误格式:
type RPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
func (e *RPCError) Error() string {
return fmt.Sprintf("RPC error %d: %s", e.Code, e.Message)
}
// 预定义错误
var (
ErrParseError = &RPCError{Code: -32700, Message: "Parse error"}
ErrInvalidRequest = &RPCError{Code: -32600, Message: "Invalid Request"}
ErrMethodNotFound = &RPCError{Code: -32601, Message: "Method not found"}
ErrInvalidParams = &RPCError{Code: -32602, Message: "Invalid params"}
ErrInternal = &RPCError{Code: -32603, Message: "Internal error"}
)
总结
通过gorilla/rpc/jsonrpc
库,我们可以方便地实现JSON-RPC 2.0协议的服务端和客户端。主要特点包括:
- 支持JSON-RPC 2.0规范
- 易于集成到现有HTTP服务中
- 支持批量请求和通知
- 提供了标准的错误处理机制
对于更简单的需求,也可以考虑使用标准库net/rpc/jsonrpc
,但它只实现了JSON-RPC 1.0规范,功能较为有限。
在实际项目中,你可能还需要考虑添加认证、限流、日志记录等中间件功能,这些都可以通过包装HTTP处理器来实现。