Создание пользователя rpc
cd
прибытьFoodGuides
Под содержанием. Создайтеrpc
папка
mkdir -p usermanage/rpc/user && cd usermanage/rpc/user
существуетrpc/user
написать в каталогuser.proto
документ
goctl rpc template -o user.proto
записыватьuser.proto
документ
syntax = "proto3";
package user;
message LoginRequest {
string email = 1;
string password = 2;
}
message RegisterRequest {
string Username = 1;
string Email = 2;
string Password = 3;
}
message UserinfoRequest {
string Userid = 1;
string Token = 2;
}
message Response {
int64 id = 1;
string email = 2;
string accessToken = 3;
int64 accessExpire = 4;
int64 refreshAfter = 5;
}
service User {
rpc Login(LoginRequest) returns(Response);
rpc Register(RegisterRequest) returns(Response);
rpc Userinfo(UserinfoRequest) returns(Response);
}
Мы определяем три интерфейса:Login Register UserInfo
генерироватьuser-rpc
Служить
goctl rpc proto -src user.proto -dir .
Проверьте этоrpc/user
содержание
➜ user git:(master) ✗ tree
.
├── etc
│ └── user.yaml
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ ├── loginlogic.go
│ │ ├── registerlogic.go
│ │ └── userinfologic.go
│ ├── server
│ │ └── userserver.go
│ └── svc
│ └── servicecontext.go
├── user
│ └── user.pb.go
├── user.go
├── user.proto
└── userclient
└── user.go
8 directories, 11 files
➜ user git:(master) ✗
API Gateway
код вызоваuser rpc
Служить
редактироватьapi/etc
внизuser-api.yaml
файл, добавитьuser.rpc
настроить
Name: user-api
Host: 0.0.0.0
Port: 8888
User:
Etcd:
Hosts:
- localhost:2379
Key: user.rpc
редактироватьapi/internal/config
внизconfig.go
файл, добавитьUser
Переменная
type Config struct {
rest.RestConf
User zrpc.RpcClientConf
}
редактироватьapi/internal/svc
внизservicecontext.go
файл, добавитьUser
Variable , добавьте код создания экземпляра.
type ServiceContext struct {
Config config.Config
User userclient.User
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
User: userclient.NewUser(zrpc.MustNewClient(c.User)),
}
}
редактироватьapi/internal/logic
внизloginlogic.go
файл, добавить вызовuser rpc
изlogin
метод
func (l *LoginLogic) Login(req types.LoginRequest) (*types.LoginResponse, error) {
// todo: add your logic here and delete this line
resp,err := l.svcCtx.User.Login(l.ctx, &user.LoginRequest{
Email: req.Email,
Password: req.Password,
});
if err != nil {
return nil, err
}
token := types.JwtToken{
AccessToken: resp.AccessToken,
AccessExpire: resp.AccessExpire,
RefreshAfter: resp.RefreshAfter,
}
response := types.UserReply{
Id: resp.Id,
Email: resp.Email,
JwtToken: token,
}
return &types.LoginResponse{
response,
},nil
}
Определить структуру таблицы базы данных и сгенерировать код CRUD+cache
существуетusermanage
Создать подmodel
папка.
mkdir -p model & cd model
существуетmodel
под новымuser.sql
файл и напишите следующее.
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户Id',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称',
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码',
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户邮箱',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `name_index` (`name`),
UNIQUE KEY `email_index` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
существуетmodel
Выполните следующую команду в каталоге для созданияCRUD+cache
код,-c
указать использованиеredis cache
goctl model mysql ddl -c -src user.sql -dir .
Проверитьmodel
Структура каталогов
➜ model git:(master) ✗ tree
.
├── user.sql
├── usermodel.go // CRUD+cache代码
└── vars.go // 定义常量和变量
на этой машинеmysql
создан вfoodguides
базу данных и создать новуюuser
поверхность.
добавить часть данных
INSERT INTO `foodguides`.`user`(`id`, `name`, `password`, `email`) VALUES (1, 'Ningxi', 'd89617870c6f8a028f5728be69cc09d4cd3585b4651b7f206f1cd674bb4351ec', 'ningxi@ningxi.com');
rpc
код вызоваcrud+cache
код
редактироватьrpc/user/etc
внизuser.yaml
файл, добавьте следующее содержимое.
Обратите внимание здесьmysql
используетningxi-compose
Бегdocker
контейнер, поэтому параметры требуют внимания.
DataSource: root:2e70F5E6@(localhost:13306)/foodguides?parseTime=true
Table: user
Cache:
- Host: localhost:16379
AccessSecret: ad879037-d3fd-tghj-112d-6bfc35d54b7d
AccessExpire: 86400
Salt: ^&yh
редактироватьrpc/user/internal/config
внизconfig.go
файл, добавитьDataSource Cache AccessSecret AccessExpire
Переменная
type Config struct {
zrpc.RpcServerConf
DataSource string
Cache cache.CacheConf
AccessSecret string
AccessExpire int64
Salt string
}
редактироватьrpc/user/internal/svc
внизserviceContext.go
файл, добавитьModel
Variable , добавьте код создания экземпляра.
type ServiceContext struct {
Config config.Config
Model model.UserModel
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
Model: model.NewUserModel(sqlx.NewMysql(c.DataSource),c.Cache),
}
}
редактироватьrpc/user/internal/logic
внизloginlogic.go
файл, добавьте следующий код
func (l *LoginLogic) Login(in *user.LoginRequest) (*user.Response, error) {
res, err := l.svcCtx.Model.FindOneByEmail(in.Email)
if err == nil {
passwords := ningxi.PasswordEncrypt(l.svcCtx.Config.Salt,in.Password)
if passwords == res.Password {
now := time.Now().Unix()
accessExpire := l.svcCtx.Config.AccessExpire
jwtToken, err := l.getJwtToken(l.svcCtx.Config.AccessSecret, now, accessExpire, res.Id)
if err != nil {
return nil, err
}
response := user.Response{
Email: res.Email,
Id: res.Id,
AccessToken: jwtToken,
AccessExpire: now + accessExpire,
RefreshAfter: now + accessExpire/2,
}
return &response, nil
} else {
return nil, errors.New("密码错误")
}
}
return nil, err
}
я здесьloginlogic
добавлено вtoken
Сгенерируйте соответствующий код для шифрования и проверки пароля, чтобы, когда пользователь успешно войдет в систему, мы сгенерировалиtoken
возвращен клиенту.
Исправлятьapi
response
Обратный формат
Я надеюсь, что формат возврата данных запроса клиентского интерфейса будет таким
{
"code": 1,
"message": "",
"result": {
"id": 1,
"username": "",
"email": "ningxi@ningxi.com",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MTE0NzAzOTQsImlhdCI6MTYxMTM4Mzk5NCwidXNlcklkIjoxfQ.8EJU0XDZ535NZvtCPgyOg9RVw3FAdG5AJktHYcjEGo0",
"accessExpire": 1611470394,
"refreshAfter": 1611427194
}
}
существуетfoodguides
добавить в папкуningxi
папку и создатьningxi.go
файл, добавьте следующий код
import (
"fmt"
"golang.org/x/crypto/scrypt"
)
type HttpResponse struct {
Code int `json:"code"`
Message string `json:"message"`
Result interface{} `json:"result"`
}
func SuccessResponse(resData interface{},message string) HttpResponse {
return HttpResponse{Code:1,Message: message,Result: resData}
}
func FailureResponse(resData interface{},message string,code int) HttpResponse {
return HttpResponse{Code:code,Message: message,Result: resData}
}
func PasswordEncrypt(salt,password string) string {
dk,_ := scrypt.Key([]byte(password), []byte(salt), 32768, 8, 1, 32)
return fmt.Sprintf("%x",string(dk))
}
Отредактируйте loginhandler.go в разделе api/internal/handler и добавьте следующий код.
func LoginHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.LoginRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.OkJson(w, ningxi.FailureResponse(nil,err.Error(),1000))
return
}
l := logic.NewLoginLogic(r.Context(), ctx)
resp, err := l.Login(req)
if err != nil {
httpx.OkJson(w, ningxi.FailureResponse(nil,err.Error(),1000))
} else {
httpx.OkJson(w, ningxi.SuccessResponse(resp,""))
}
}
}
запустить службу
Запустите службу, обратите внимание, что перед запуском службы необходимо убедиться, что используется та, которая использовалась в предыдущей статье.ningxi-compose
беги нормально.
запускатьuser rpc
служба, после успешного запуска,user rpc
бегать по локалке8080
порт
➜ FoodGuides git:(master) ✗ go run usermanage/rpc/user/user.go -f usermanage/rpc/user/etc/user.yaml
Starting rpc server at 127.0.0.1:8080...
запускатьuser api
служба, после успешного запуска,user api
бегать по локалке8888
порт
➜ FoodGuides git:(master) ✗ go run usermanage/api/user.go -f usermanage/api/etc/user-api.yaml
Starting server at 0.0.0.0:8888...
api
Проверка Если получены следующие данные, служба работает нормально
➜ ~ curl http://localhost:8888/users/login -X POST -d '{"email": "ningxi@ningxi.com","password": "809161"}' --header "Content-Type: application/json"
{"code":1,"message":"","result":{"id":1,"username":"","email":"ningxi@ningxi.com","accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MTE0OTU3MjAsImlhdCI6MTYxMTQwOTMyMCwidXNlcklkIjoxfQ.EN9og9owK5eW--qUIJCf0UvMKNaeenVac1lmMQFcHSM","accessExpire":1611495720,"refreshAfter":1611452520}}%
➜ ~
Понять, как работает сервис
Старый способ — понять процесс выполнения сервиса
-
user/etc
внизuser.yaml
документ. Этот файл настраиваетuser rpc
Некоторые переменные, требуемые службой, это то же самое, что иapi
Обслуживание такое же. -
user
внизuser.proto
документ. Этот файл определяетuser rpc
Информация об интерфейсе, предоставляемая службой, и последующие добавления интерфейса также обрабатываются здесь. тогда позвониgoctl
Восстановите службу. -
user
внизuser.go
документ. Файлuser rpc
Входной файл для службы, здесь все начинается. -
user/user
внизuser.pb.go
документ. Файлuser.proto
генерироватьrpc
служебный файл, содержащийrpc
серединаclient
а такжеserver
реализация.
папка пользователя-клиента
userclient
внизuser.go
файлrpc
обслуживаниеclient
Конкретный код реализации файла реализуетuser.pb.go
три интерфейса в
User interface {
Login(ctx context.Context, in *LoginRequest) (*Response, error)
Register(ctx context.Context, in *RegisterRequest) (*Response, error)
Userinfo(ctx context.Context, in *UserinfoRequest) (*Response, error)
}
когдаapi
в сервисеserviceContext.go
в инициализацииuserclient
час,api
Сервис имеет возможность вызова этих трех интерфейсов
type ServiceContext struct {
Config config.Config
User userclient.User
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
User: userclient.NewUser(zrpc.MustNewClient(c.User)),
}
}
внутренняя папка
rpc
Внутренний код реализации в сервисе находится в этой папке.
internal/config
внизconfig.go
документ. Вы обнаружите, что файл определяет иuser.yaml
определение аналогичное. да.user.yaml
существуетuser.go
Входной файл находится вmain
метод, он анализируется какconfig
объект. Так что их значения взаимно однозначно соответствуют.
internal/logic
внизxxxlogic.go
файл, здесь реализована окончательная бизнес-логика.
internal/svc
внизservicecontext.go
документ. Файл сохраненrpc
Услугиconfig
Объект, объект подключения к базе данных Модель. пройти черезUserServer
объект переданlogic
в объекте.
internal/sercer
внизuserserver.go
документ. Файлuser rpc
обслуживаниеserver
Конкретный код реализации ,userserver
сохраненsvc.ServiceContext
объект и реализует три интерфейса
func (s *UserServer) Login(ctx context.Context, in *user.LoginRequest) (*user.Response, error) {
l := logic.NewLoginLogic(ctx, s.svcCtx)
return l.Login(in)
}
func (s *UserServer) Register(ctx context.Context, in *user.RegisterRequest) (*user.Response, error) {
l := logic.NewRegisterLogic(ctx, s.svcCtx)
return l.Register(in)
}
func (s *UserServer) Userinfo(ctx context.Context, in *user.UserinfoRequest) (*user.Response, error) {
l := logic.NewUserinfoLogic(ctx, s.svcCtx)
return l.Userinfo(in)
}
когдаapi
обслуживание черезuserclient
перечислитьrpc
При подаче,userserver
Запустит соответствующий метод и, наконец, вызовет соответствующийlogic
метод.
Подведение итогов процесса вызова
В качестве примера возьмем клиент, вызывающий интерфейс входа в систему.
client
часть
api
Когда служба запускается, она инициализируетсяuserclient
объект, поэтомуapi
Сервис имеет звонокuser rpc
способность служить
type ServiceContext struct {
Config config.Config
User userclient.User
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
User: userclient.NewUser(zrpc.MustNewClient(c.User)),
}
}
server
часть
user.go
входной файл черезyaml
конфигурационный файл, экземплярconfig
объект.
var configFile = flag.String("f", "etc/user.yaml", "the config file")
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
}
создавать экземплярServiceContext
объект
ctx := svc.NewServiceContext(c)
создавать экземплярUserServer
объект
srv := server.NewUserServer(ctx)
создавать экземплярrpc
Служить
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
user.RegisterUserServer(grpcServer, srv)
})
user.RegisterUserServer(grpcServer, srv)
сделал что-то вродеapi
Функцию реализует маршрут в сервисе.
запускатьrpc
Служить
s.Start()
когдаapi
обслуживание черезclient
перечислитьlogin
способ,rpc server
вызоветuserserve
серединаlogin
метод.
func (s *UserServer) Login(ctx context.Context, in *user.LoginRequest) (*user.Response, error) {
l := logic.NewLoginLogic(ctx, s.svcCtx)
return l.Login(in)
}
login
вызов методаlogic
серединаlogin
метод
После обработки данных интерфейс отвечает слой за слоем и, наконец, завершает вызов клиентского интерфейса.
Содержание этого фильма относительно длинное, в которомJwtToken
,rpc
серединаclient
а такжеserver
Другие связанные знания, вы можете проверить информацию самостоятельно, чтобы лучше понять содержание учебника.