目录
在现代分布式应用开发中,将 RPC 服务与 API 相结合是一种常见且有效的架构模式。RPC 服务专注于内部业务逻辑的实现和高效的服务间通信,而 API 则提供对外的接口,方便与前端或其他外部系统进行交互。本文将详细介绍如何实现 RPC 服务与 API 的结合,包括创建项目结构、编写 proto 文件、生成代码、配置服务、编写 API 逻辑以及实现服务调用等步骤,并附上相应的代码示例。
一、项目结构规划
- 创建项目目录
- 新建一个项目目录,例如
rpc_api_demo。 - 在项目目录下创建
rpc和api目录,分别用于存放 RPC 相关文件和 API 相关文件。
- 新建一个项目目录,例如
- RPC 服务目录结构
- 在
rpc目录下创建user目录(以用户服务为例),用于存放用户相关的 RPC 服务文件。 - 在
user目录下创建etc、internal和model目录(model目录用于存放与数据库交互相关的模型代码,若不涉及数据库操作可暂不创建)。etc目录存放服务配置文件,internal目录存放服务内部逻辑代码。
- 在
- API 目录结构
- 在
api目录下创建user目录,用于存放用户相关的 API 文件。 - 在
user目录下创建etc、internal和logic目录。etc目录存放 API 配置文件,internal目录存放 API 相关的结构体和接口定义,logic目录存放 API 的具体逻辑实现。
- 在
二、编写 RPC 服务的 proto 文件
- 创建 user.proto 文件(rpc/user)
- 在
rpc/user目录下创建user.proto文件。 - 定义服务接口,例如创建一个名为
UserRpc的服务,包含GetUser方法用于根据用户 ID 获取用户信息,CreateUser方法用于创建新用户等。 - 示例代码如下:
- 在
syntax = "proto3";
service UserRpc {
rpc GetUser (GetUserRequest) returns (GetUserResponse);
rpc CreateUser (CreateUserRequest) returns (CreateUserResponse);
}
message GetUserRequest {
int32 id = 1;
}
message GetUserResponse {
int32 id = 1;
string name = 2;
string email = 3;
}
message CreateUserRequest {
string name = 1;
string email = 2;
}
message CreateUserResponse {
int32 code = 1;
string message = 2;
}
三、生成 RPC 服务代码
- 执行生成命令
- 在终端中,进入
rpc目录(确保已安装goctl工具)。 - 执行以下命令将
user.proto文件转换为对应的 GO 代码:
- 在终端中,进入
goctl proto -I. --go_out=. --go-grpc_out=. user.proto
- 此命令会在
rpc目录下生成一系列文件,包括user.pb.go和user_grpc.pb.go等,这些文件包含了 RPC 服务的客户端和服务端的基本代码结构,以及与 proto 文件中定义的消息和服务对应的 Go 结构体和接口。
四、编写 RPC 服务逻辑
- 在 internal 目录下编写逻辑代码(rpc/user/internal/logic)
- 以
GetUser方法为例,在rpc/user/internal/logic/userrpcgetuserlogic.go文件中实现其逻辑。假设这里涉及数据库查询操作(若不涉及则可根据实际业务逻辑编写),首先需要配置数据库连接(参考之前关于 RPC 服务使用 GORM 的部分)。 - 示例代码如下(假设已经配置好数据库连接并创建了
User模型结构体和操作方法):
- 以
package logic
import (
"context"
"rpc_api_demo/rpc/internal/svc"
"rpc_api_demo/rpc/types/demo"
"rpc_api_demo/rpc/user/model"
)
type UserRpcGetUserLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUserRpcGetUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserRpcGetUserLogic {
return &UserRpcGetUserLogic{
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *UserRpcGetUserLogic) GetUser(in *demo.GetUserRequest) (*demo.GetUserResponse, error) {
// 获取数据库连接
db := l.svcCtx.DB
// 创建User模型实例
userModel := model.User{DB: db}
// 调用模型方法查询用户信息
user, err := userModel.FindUserByID(db, in.Id)
if err!= nil {
return nil, err
}
return &demo.GetUserResponse{Id: user.ID, Name: user.Name, Email: user.Email}, nil
}
- 同样,在
rpc/user/internal/logic/userrpccreateuserlogic.go文件中实现CreateUser方法的逻辑,例如将新用户信息插入数据库并返回相应结果。
五、配置 RPC 服务
- 在 etc 目录下创建配置文件(rpc/user/etc/user.yaml)
- 在
rpc/user/etc目录下创建user.yaml文件。 - 配置服务的相关信息,如服务名称、监听地址和端口等,若涉及数据库操作还需配置数据库连接信息。
- 示例配置如下(假设使用 MySQL 数据库):
- 在
Name: userrpc
Host: 0.0.0.0
Port: 8080
Mysql:
DataSource: root:root@tcp(127.0.0.1:3306)/your_database?charset=utf8mb4&parseTime=True&loc=Local
- 将
your_database替换为实际的数据库名,根据实际情况修改用户名、密码和端口号等。
六、编写 API 的相关文件
- 编写 user.api 文件(api/user)
- 在
api/user目录下创建user.api文件。 - 定义 API 接口,例如创建获取用户信息的接口和创建用户的接口,与 RPC 服务中的方法相对应。
- 示例代码如下:
- 在
// 获取用户信息接口
// @Summary 获取用户信息
// @Description 根据用户ID获取用户详细信息
// @Tags 用户管理
// @Accept json
// @Produce json
// @Param id path int true "用户ID"
// @Success 200 {object} types.UserInfoResponse "获取用户信息成功"
// @Router /user/{id} [get]
// 创建用户接口
// @Summary 创建用户
// @Description 创建新用户
// @Tags 用户管理
// @Accept json
// @Produce json
// @Param user body types.CreateUserRequest true "用户信息"
// @Success 200 {object} types.CreateUserResponse "创建用户成功"
// @Router /user [post]
- 这里使用了注释来描述接口的功能、参数、响应等信息,遵循一定的规范,方便生成 API 文档和前后端协作。
七、生成 API 代码
- 执行生成命令
- 在终端中,进入
api目录。 - 执行以下命令将
user.api文件转换为对应的 GO 代码:
- 在终端中,进入
goctl api go -api user.api -dir.
- 此命令会在
api目录下生成一系列文件,包括handler、logic等相关文件,构建了 API 的基本框架。
八、编写 API 逻辑实现服务调用
- 在 logic 目录下编写逻辑代码(api/user/logic)
- 以获取用户信息接口为例,在
api/user/logic/userinfologic.go文件中实现其逻辑。 - 首先需要创建 RPC 服务客户端连接,然后调用 RPC 服务的
GetUser方法获取用户信息并返回给 API 调用者。 - 示例代码如下:
- 以获取用户信息接口为例,在
package logic
import (
"context"
"rpc_api_demo/api/internal/svc"
"rpc_api_demo/api/internal/types"
"rpc_api_demo/rpc/types/demo"
"rpc_api_demo/rpc/user/userclient"
"github.com/zeromicro/go-zero/zrpc"
)
type UserInfoLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserInfoLogic {
return &UserInfoLogic{
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *UserInfoLogic) UserInfo(req *types.UserInfoReq) (resp *types.UserInfoResp, err error) {
// 创建RPC服务客户端连接
userRpcConn := zrpc.MustNewClient(zrpc.RpcClientConf{
Endpoints: []string{"127.0.0.1:8080"},
})
userRpc := userclient.NewUserRpcClient(userRpcConn)
// 调用RPC服务的GetUser方法
userResp, err := userRpc.GetUser(context.Background(), &demo.GetUserRequest{Id: req.Id})
if err!= nil {
return nil, err
}
return &types.UserInfoResp{Id: userResp.Id, Name: userResp.Name, Email: userResp.Email}, nil
}
- 对于创建用户接口,在
api/user/logic/createuserlogic.go文件中实现,调用 RPC 服务的CreateUser方法并处理响应。
九、配置 API 服务
- 在 etc 目录下创建配置文件(api/user/etc/user.yaml)
- 在
api/user/etc目录下创建user.yaml文件。 - 配置 API 服务的相关信息,如端口号等。
- 示例配置如下:
- 在
port: 8888
十、启动服务
- 启动 RPC 服务
- 在终端中,进入
rpc/user目录。 - 执行
go run main.go(或者go run user.go,根据实际文件名而定)启动 RPC 服务。
- 在终端中,进入
- 启动 API 服务
- 进入
api/user目录。 - 执行
go run user.go启动 API 服务。
- 进入
通过以上步骤,我们成功地实现了 RPC 服务与 API 的结合。在实际应用中,这种架构可以充分发挥 RPC 服务和 API 的优势,实现高效的内部业务处理和友好的外部接口提供。同时,可以进一步优化和扩展,如添加服务治理、安全认证、缓存机制等,以构建更加稳定、可靠和高效的分布式应用系统。希望本文能够帮助大家更好地理解和应用 RPC 服务与 API 的结合技术。
170万+

被折叠的 条评论
为什么被折叠?



