当前位置: 首页 > news >正文

全免费建立自己的网站wordpress注册表文件夹

全免费建立自己的网站,wordpress注册表文件夹,多用户商城系统哪个好用,网站开发与网页制作难不难文章目录用户微服务表结构查表web 服务跨域问题图形验证码短信用户注册服务中心注册 grpc 服务动态获取端口负载均衡配置中心启动项目小结用户微服务 作为系统的第一个微服务#xff0c;开发的技术点前面已经了解了一遍#xff0c;虽有待补充#xff0c;但急需实战这里主要… 文章目录用户微服务表结构查表web 服务跨域问题图形验证码短信用户注册服务中心注册 grpc 服务动态获取端口负载均衡配置中心启动项目小结用户微服务 作为系统的第一个微服务开发的技术点前面已经了解了一遍虽有待补充但急需实战这里主要梳理架构和开发步骤为整个开发定下基调go version 升到 1.20 表结构 在 model 定义用户表结构技术点gorm 密文保存密码使用信息摘要算法 md5 配合盐值使用工具可指定使用的算法验证密码采用比较普遍的做法将算法、盐值、密码拼接存入数据库 将表创建_ db.AutoMigrate(model.User{}) 查表 在 proto 文件定义需要的方法请求参数返回值技术点protobuf 主要是数据库相关的操作 生成代码handler 中实现接口中定义的方法即 server 端逻辑 protoc -I . user.proto --go_outpluginsgrpc:.返回值一定要严格按照 message 定义type UserServer interface {GetUserList(context.Context, *PageInfo) (*UserListResponse, error)GetUserByMobile(context.Context, *MobileRequest) (*UserInfoResponse, error)GetUserById(context.Context, *IdRequest) (*UserInfoResponse, error)CreateUser(context.Context, *CreateUserInfo) (*UserInfoResponse, error)UpdateUser(context.Context, *UpdateUserInfo) (*emptypb.Empty, error)CheckPassWord(context.Context, *PasswordCheckInfo) (*CheckResponse, error) }GetUserList/GetUserById 使用 gorm 的 DB struct 和分页方法定义将 model struct 转换为 message response 的函数 GetUserByMobile 使用 config viper 配合 yaml 文件做全局配置可以回顾前面的文章使用 grpc 的 status 返回状态信息日志和错误处理很重要 UpdateUser 处理时间time.Unix(int64(req.BirthDay) 验证密码 使用工具的 Verify 函数 web 服务 上面的用户微服务是 service 层接下来通过 gin 将 service 层的 api 暴露出来也就是 client 端 API 当然先从 user-web 开始api/user.go也可以通过 grpc 的 gateway 暴露 日志配置使用 zap 将日志输出到文件可以回顾前面的文章或者看官方教程 用 Sugar 会损失一些性能反射判断类型但是好用配置 zap.S() 初始化放在 initialize 初始化 Router : gin.Default()只能有一个通过 Group 添加分组初始化日志把server 端的 proto 文件拿过来生成 stub开始编写客户端调用client 端和页面在这里是前端转换 grpc status 为 HTTP status code在 global/user.go 定义格式 得到 server 端的 response 可以直接用 map[sting]interface{} 存用户信息但是切片不够优雅为前端定义 UserResponse struct实例化 user 再加入 []interface{}为 birthday 重写 MarshalJSON 方法返回指定的时间格式 配置文件管理工具技术点viper 将文件解析成内部的 struct 是 go 语言中非常常见的操作上面为返回值定义 struct 也是一样的道理在 go 环境中操作自然是 struct 更方便定义 struct 时打 tag 也是这个作用把文件/json体中的数据映射成 struct 字段值viper 可以自动将 yaml 文件解析成 struct将线上和线下配置文件隔离在本地设置环境变量比如 SHOP_DEBUGtrue代表开发环境func GetEnvInfo(env string) bool {viper.AutomaticEnv()return viper.GetBool(env)//刚才设置的环境变量 想要生效 我们必须得重启goland }服务器启动后使用 v.WatchConfig() 配合 fsnotify 监听配置文件变化v.AddConfigPath(configFileName) viper.WatchConfig() // 要放在 AddConfigPath 之后 viper.OnConfigChange(func(e fsnotify.Event) {fmt.Println(Config changed., e.Name) }) err : viper.ReadConfig() err : viper.Unmarshal()后面会引入分布式服务的配置中心接口API和前端页面都可以通过 yapi 做 mock 测试有的接口也可以写 UT 测试可以回顾前面的文章一些组件的使用方法可以临时新建目录写 demo 测试注初始化操作的调用和配置文件的加载都是在 main.go入口嘛 密码登录 PassWordLogin 表单验证可以回顾前面的文章这部分都是用验证器实现初始化 validator 中实现本地化多语言通过修改 binding.Validator 引擎的属性自定义手机号验证器并注册到 gin/binding注册个 tag表单字段的验证也是用这个也要给自定义的验证器注册翻译器binding 中定义好的验证器比如 required已经通过修改引擎实现了翻译import (regexp// 用 v10github.com/go-playground/validator/v10 )func ValidateMobile(fl validator.FieldLevel) bool {mobile : fl.Field().String()//使用正则表达式判断是否合法ok, _ : regexp.MatchString(^1([38][0-9]|14[579]|5[^4]|16[6]|7[1-35-8]|9[189])\d{8}$, mobile)if !ok{return false}return true }// main.go //注册validator/中的验证器验证手机号 if v, ok : binding.Validator.Engine().(*validator.Validate); ok {_ v.RegisterValidation(mobile, myvalidator.ValidateMobile)_ v.RegisterTranslation(mobile, global.Trans, func(ut ut.Translator) error {return ut.Add(mobile, {0} 非法的手机号码!, true) // see universal-translator for details}, func(ut ut.Translator, fe validator.FieldError) string {t, _ : ut.T(mobile, fe.Field())return t}) }验证密码的逻辑就是先根据手机号查询再比对密码使用 proto 中的方法已经在server端定义好注意参数形式对照 proto 文件写关键在于验证通过后的处理使用 sessionId 还是 token session 机制 在单体应用中登录成功会返回 sessionId 存在 cookie表明身份 在微服务中由于服务之间隔离在用户服务保存的 sessionid 不能在商品服务验证需要有个公用的数据库 但我们不用上面的方案而是采用更方便的 JWTjson web token JWT 基础知识一般放在浏览器的 Headers 中可以自定义名称比如 x-tokenJWT 相关代码是通用的放在 middlewares下面models 下定义 payload struct payload 不能放敏感信息因为是没有加密的我们只是通过 Signature 部分判断 token 有效性secret 只存在服务器一定不能泄露类似对称加密私钥签私钥解如何保证JWT的安全呢一般会把过期时间设置短一些可以在官网测试一下生成的 token 然后给 URL 添加 token 验证 使用鉴权函数 JWTAuth()因为是作为中间件要注册的所以写法上是返回函数 return func(c *gin.Context)鉴权后使用c.Set()将登录用户的信息保存在 context方便后端获取URL 的鉴权在 router 中添加 middlewares.JWTAuth() 即可如果是个整个 Group 添加直接用 .Use(middlewares.JWTAuth()) 验证是否为管理员 还是在 middlewares 定义鉴权函数用刚保存的 context 获取 AuthorityId如果为 2 则是管理员Role Id 是在登录时就从数据库获取并保存在 token可以做基于 Role 的访问控制RBAC对访问 API 做控制 更多注释在代码中可以 clone 代码研究 跨域问题 跨域protocol/ip/port 不一致一般会报 404在发起复杂请求且跨域时这种情况很常见浏览器出于安全性考虑会发起 OPTIONS 预检请求 预检是 CORS跨域资源共享 中一种透明服务器验证机制。预检请求首先需要向另外一个域名的资源发送一个 HTTP OPTIONS 请求头其目的是为了判断实际发送的请求是否是安全的测试代码本地请求用户列表会跨域!DOCTYPE html html langen headmeta charsetUTF-8titleTitle/titlescript srchttp://libs.baidu.com/jquery/2.0.0/jquery.min.js/script /head bodybutton typebutton idquery请求数据/buttondiv idcontent stylebackground-color: aquamarine; width: 300px;height: 500px;/div /body script typetext/javascript$(#query).click(function () {$.ajax({url:http://127.0.0.1:8021/u/v1/user/list,dataType: json,type: get,beforeSend: function(request) {request.setRequestHeader(x-token, eyJhbGciOiJIUzI1NiIsInR5cC)},success: function (result) {console.log(result.data);$(#content).text(result.data);},error: function (data) {alert(请求出错)});}); /script /html跨域可以在前端或者后端解决 这里我们在后端解决还是使用中间件 cors.go设置 Header 字段 Access-Control-Allow-Methodspackage middlewaresimport (github.com/gin-gonic/ginnet/http )func Cors() gin.HandlerFunc {return func(c *gin.Context) {method : c.Request.Methodc.Header(Access-Control-Allow-Origin, *)c.Header(Access-Control-Allow-Headers, Content-Type,AccessToken,X-CSRF-Token, Authorization, Token, x-token)c.Header(Access-Control-Allow-Methods, POST, GET, OPTIONS, DELETE, PATCH, PUT)c.Header(Access-Control-Expose-Headers, Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type)c.Header(Access-Control-Allow-Credentials, true)// 不需要预检直接 abort再请求原地址即可if method OPTIONS {c.AbortWithStatus(http.StatusNoContent)}} }在初始化时配置跨域Router.Use(middlewares.Cors()) 图形验证码 参考文档相关逻辑放在 api/captcha.go这块路由我们新建 BaseRouter全局变量 storeis a shared storage for captchas同一个包目录内的 go 文件都可以用 提供了 Verify 方法验证通过 form 传过来的验证码 在登录表单中加上 Captcha 和 CaptchaId 验证之后当前验证码就会失效已经从变量中删除 短信 用户注册或动态登录需要短信验证码使用阿里云的服务去控制台申请 code代码是固定的添加配置type RedisConfig struct {Host string mapstructure:host json:hostPort int mapstructure:port json:portExpire int mapstructure:expire json:expire // 短信过期时间 } type AliSmsConfig struct {ApiKey string mapstructure:key json:keyApiSecrect string mapstructure:secrect json:secrect }把发出去的验证码存在 Redis也能设置过期时间rdb.Set(context.Background(), sendSmsForm.Mobile, smsCode, time.Duration(global.ServerConfig.RedisInfo.Expire)*time.Second)给前端返回 “发送成功” 即可前端部分用户输入验证码自然需要定义表单了 一般咱们写 API 的逻辑是从前端到后端便于明确需求和参数当然前端页面也要结合后端的设计但总的来说应该先有前端的需求和项目的架构绘制 Draft 界面 以上是 SendSms 接口给前端调的但依托于两处验证才会用到动态登录用户注册 用户注册 最后一个 API前端需要接收用户的注册参数client 端调用后端的 CreateUser 即可我们从定义表单开始采用注册成功自动登录的逻辑就不跳转到登录页面让用户再次输入了 在这里创建 JWT并返回和密码登录逻辑一样的数据即可// 返回给这些值就代表登录成功 c.JSON(http.StatusOK, gin.H{id: user.Id,nick_name: user.NickName,token: token,expired_at: (time.Now().Unix() 60*60*24*30) * 1000, })用户发起 ajax 请求并根据返回字段判断是否登录成功 服务中心 有很多服务注册和发现的工具这里我们选择 consul支持健康检查和 DNS前面的文章中整理过可以写 python 代码测试 consul 的接口也可以使用 postman 这篇文章底层使用 python 编写 grpc 服务但道理是相通的 用 go 调用一下 consul 的各接口方便后续接入package mainimport (fmtgithub.com/hashicorp/consul/api )func Register(address string, port int, name string, tags []string, id string) error {cfg : api.DefaultConfig()cfg.Address 192.168.1.103:8500client, err : api.NewClient(cfg)if err ! nil {fmt.Println(err)}//生成对应的检查对象check : api.AgentServiceCheck{HTTP: http://192.168.1.102:8021/health,Timeout: 5s,Interval: 5s,DeregisterCriticalServiceAfter: 10s,}//生成注册对象// 两种方式//registration : api.AgentServiceRegistration{// Kind: ,// ID: ,// Name: ,// Tags: nil,// Port: 0,// Address: ,// SocketPath: ,// TaggedAddresses: nil,// EnableTagOverride: false,// Meta: nil,// Weights: nil,// Check: nil,// Checks: nil,// Proxy: nil,// Connect: nil,// Namespace: ,// Partition: ,//}// 我们使用 new 实例化structregistration : new(api.AgentServiceRegistration)registration.Name nameregistration.ID idregistration.Port portregistration.Tags tagsregistration.Address addressregistration.Check checkerr client.Agent().ServiceRegister(registration)// client.Agent().ServiceDeregister()if err ! nil {fmt.Println(err)}return nil }func AllServices() {cfg : api.DefaultConfig()cfg.Address 192.168.1.103:8500client, err : api.NewClient(cfg)if err ! nil {panic(err)}data, err : client.Agent().Services()if err ! nil {panic(err)}for key, _ : range data {fmt.Println(key)} } func FilterSerivice() {cfg : api.DefaultConfig()cfg.Address 192.168.1.103:8500client, err : api.NewClient(cfg)if err ! nil {panic(err)}data, err : client.Agent().ServicesWithFilter(Service user-web)if err ! nil {panic(err) // 如果报错不用管IDE 的原因}for key, _ : range data {fmt.Println(key)} }func main() {_ Register(192.168.1.102, 8021, user-web, []string{vshop, Roy}, user-web)//AllServices()//FilterSerivice()// fmt.Println(fmt.Sprintf(Service %s, user-srv)) }服务没启动时会显示这个检查结果 注册 grpc 服务 之前 user-web 通过 grpc.Dial 直接拨号连接 service 层的服务现在用服务发现注册中心代替 当然Dial 是必须的这里只不过是将 IP 和 Port 集中管理查找获取不再是写死的 先服务注册将 grpc 服务service层注册到 consul 中 GRPC 或 HTTP 都是在 AgentServiceCheck 里指明其实主要区别就是 consul 对它们健康检查的方式不一样获取服务不都是IP/Port嘛 // 这是HTTP的检查方式很简单请求 /health 能返回即可 // 生成对应的检查对象 check : api.AgentServiceCheck{HTTP: fmt.Sprintf(http://%s:%d/health, address, port),Timeout: 10s,Interval: 30s,DeregisterCriticalServiceAfter: 10s, }// 当然要在路由初始化时定义 /health Router.GET(/health, func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{code: http.StatusOK,success: true,msg: very healthy,}) })先把配置文件和日志工具集成进来同样新建 config/config.go打上 mapstructure tag为映射成 struct 做准备 加上 consul 的配置IP:Port main.go 调用 initialize 读取配置文件映射成全局 struct放在 global 下就可以开用了 数据库初始化包括数据库日志配置zap.S() 日志初始化 不同于 clientAPI层这里可以新建 test 目录使用 var userClient proto.UserClient 测试不必等到 yapi 统一测试 client 端 API不好定位问题给 grpc 服务配置健康检查grpc 本身提供了接口前面的文章也说过 实现 Check 和 Watch 方法这里只需要加一句 grpc_health_v1.RegisterHealthServer(server, health.NewServer())注册一个用于检查的 server这个 Server 还是一个 struct且实现了上述两个方法grpc/health 这个库帮我们写好了可以看源码了解是怎么检查的consul 相当于 client 端注册到 consul 之后健康检查时就调用这两个方法为啥consul健康检查时会调用注册的grpc的两个方法呢因为 consul 对 grpc 的健康检查就是这么定义的从 consul 文档中也能找到 按照上面的 demo 注册即可注意 IP 和 port user-web 使用 consul 进行服务发现调用 传统做法就是连上 consul过滤得到需要的 user_srv配置文件和相关代码如下 配置文件和 config 的 struct 一致但这里我们 service 的 host 和 port 不再是从文件获取不需要而是拿着 Name/Id 从 consul 发现并直接拨号问题也很明显就是代码很长比业务逻辑都长怎么办我们将连接 consul 获取用户服务这部分抽出来放在 initialize/srv_conn.go并返回给 global/UserSrvClient 全局使用这样做还有个好处已经事先创立好了连接这样后续就不用进行多次 tcp 的握手但也有问题如何均衡发现的多个服务呢这个问题在负载均衡部分解决 动态获取端口 本地开发环境端口号固定但线上环境需要自动获取端口号func GetFreePort() (int, error) {addr, err : net.ResolveTCPAddr(tcp, localhost:0)if err ! nil {return 0, err}l, err : net.ListenTCP(tcp, addr)if err ! nil {return 0, err}defer l.Close()return l.Addr().(*net.TCPAddr).Port, nil }网络这块后面会研究需要用 docker 部署NGINX 转发 负载均衡 什么是负载均衡前面的文章解释过 简而言之用户到网关网关到 APIAPI 到 Service之间都需要负载均衡为了抗住并发但是 API 和 Service 之间是 grpc 调用如何做负载均衡呢 负载均衡策略架构 进程内的负载均衡策略用的比较广泛自定义 SDK 不是问题要尽量避免使用第三方插件 负载均衡算法核心 使用轮询法round_robin grpc 实现负载均衡 先到 srv 部分demo 还是看前面的文章启动多个 Server 测试需要将 Serve 监听请求放在协程避免阻塞影响后续终止信号的监听因为负载均衡算法作用在 consul 和 grpc 上所以不必在一次进程中连续请求采用多次启动也能查看负载均衡的效果 集成到 user-web使用负载均衡连接 Server 端的服务import _ github.com/mbobakov/grpc-consul-resolver// 使用这个工具grpc-consul-resolver服务发现负载均衡一并实现 func InitSrvConn() {consulInfo : global.ServerConfig.ConsulInfouserConn, err : grpc.Dial(fmt.Sprintf(consul://%s:%d/%s?wait14s, consulInfo.Host, consulInfo.Port, global.ServerConfig.UserSrvInfo.Name),grpc.WithInsecure(),grpc.WithDefaultServiceConfig({loadBalancingPolicy: round_robin}),)if err ! nil {zap.S().Fatal([InitSrvConn] 连接 【用户服务失败】)}userSrvClient : proto.NewUserClient(userConn)global.UserSrvClient userSrvClient }负载均衡的代码目前只体现在 user-web 部分因为它调用 user-srv服务发现不是srv的服务注册负载均衡一并使用 grpc-consul-resolver实现按道理只要请求其他服务都应该配置负载均衡目前 user-srv 启动多个server做算法验证即可 注user-web 也需要注册到 consul因为后面也会被调用发现 配置中心 为什么使用配置中心这部分在前面的文章分析过ClientAPI端和 Server 端都要用各自启动时拉取配置再梳理一下流程 技术选型nacos安装由于nacos是基于Java的所以选择使用docker安装避免手动配置Java环境docker run --name nacos-standalone -e MODEstandalone -e JVM_XMS512m -e JVM_XMX512m -e JVM_XMN256m -p 8848:8848 -d nacos/nacos-server:latest主要关注配置管理命名空间 go nacos是 go 语言操作 nacos 的 SDK参考手册使用 写一个 go 的 demo先搭建好上面环境新建好配置 package mainimport (//encoding/jsonfmtgithub.com/nacos-group/nacos-sdk-go/clientsgithub.com/nacos-group/nacos-sdk-go/common/constantgithub.com/nacos-group/nacos-sdk-go/vo//shop_srvs/temp/config )func main() {// nacos的地址sc : []constant.ServerConfig{{IpAddr: 192.168.109.128,Port: 8848,},}// nacos的client地址cc : constant.ClientConfig{NamespaceId: 26195427-54f4-4a0b-8b25-29e7b654686b, // 如果需要支持多namespace我们可以创建多个client,它们有不同的NamespaceIdTimeoutMs: 5000,NotLoadCacheAtStart: true,LogDir: tmp/nacos/log, // 日志和缓存目录要配置CacheDir: tmp/nacos/cache,LogLevel: debug,}// 动态配置客户端到这一步相当于定位到了nacos的一个命名空间里接下来只需传入ID和GroupconfigClient, err : clients.CreateConfigClient(map[string]interface{}{serverConfigs: sc,clientConfig: cc,})// 创建动态配置客户端的另一种方式 (推荐)//configClient, err : clients.NewConfigClient(// vo.NacosClientParam{// ClientConfig: clientConfig,// ServerConfigs: serverConfigs,// },//)if err ! nil {panic(err)}// 命名空间groupID 唯一定位content, err : configClient.GetConfig(vo.ConfigParam{DataId: user-web,Group: dev})if err ! nil {panic(err)}fmt.Println(content) //字符串 - json//serverConfig : config.ServerConfig{}//想要将一个json字符串转换成struct需要去设置这个struct的tag//json.Unmarshal([]byte(content), serverConfig)//fmt.Println(serverConfig)//err configClient.ListenConfig(vo.ConfigParam{// DataId: user-web.json,// Group: dev,// OnChange: func(namespace, group, dataId, data string) {// fmt.Println(配置文件变化)// fmt.Println(group: group , dataId: dataId , data: data)// },//})//time.Sleep(3000 * time.Second) }代码包括了将获取到的配置映射成 struct如果我们的配置文件是yaml格式可以换成 jsongo内置支持的映射方式这是目前我们项目 user-web 部分的所有配置字段package configtype UserSrvConfig struct {Host string mapstructure:host json:hostPort int mapstructure:port json:portName string mapstructure:name json:name }type JWTConfig struct {SigningKey string mapstructure:key json:key }type AliSmsConfig struct {ApiKey string mapstructure:key json:keyApiSecrect string mapstructure:secrect json:secrect }type ConsulConfig struct {Host string mapstructure:host json:hostPort int mapstructure:port json:port }type RedisConfig struct {Host string mapstructure:host json:hostPort int mapstructure:port json:portExpire int mapstructure:expire json:expire }type ServerConfig struct {Name string mapstructure:name json:namePort int mapstructure:port json:portUserSrvInfo UserSrvConfig mapstructure:user_srv json:user_srvJWTInfo JWTConfig mapstructure:jwt json:jwtAliSmsInfo AliSmsConfig mapstructure:sms json:smsRedisInfo RedisConfig mapstructure:redis json:redisConsulInfo ConsulConfig mapstructure:consul json:consul }集成到 user-web 总配置文件 config-dev.yamlhost: 192.168.109.128 port: 8848 namespace: 26195427-54f4-4a0b-8b25-29e7b654686b user: nacos password: nacos dataid: user-web group: devconfig/config.go 新增 nacos 的配置项在初始化 InitConfig 里用 viper 读取并映射成 struct 操作type NacosConfig struct {Host string mapstructure:hostPort uint64 mapstructure:portNamespace string mapstructure:namespaceUser string mapstructure:userPassword string mapstructure:passwordDataId string mapstructure:dataidGroup string mapstructure:group }集成到 user_srv 和上面的过程类似如何监听 nacos 的配置文件总配置的变化呢使用 viper如何监听远程配置文件的变化呢 启动项目 环境准备 MySQLinitialize 里只做了初始化连接数据库需要先手动创建表handler 里如何确定表名model.User作为参数即可吗docker run \ --name mysql \ -d \ -p 3306:3306 \ --restart unless-stopped \ -v /mydata/mysql/log:/var/log/mysql \ -v /mydata/mysql/data:/var/lib/mysql \ -v /mydata/mysql/conf:/etc/mysql \ -e MYSQL_ROOT_PASSWORD123456 \ mysql:5.7-- 按道理容器暴露出3306端口远程即可连接但要检查网络是否通畅 -- https://blog.csdn.net/cljdsc/article/details/115207336-- 手动创建数据库user-srv 服务使用 create database shop_user_srv default charset utf8 collate utf8_general_ci;手动创建表func main() {// 手动创建数据库 vshop_user_srvdsn : root:123456tcp(192.168.109.128:3306)/shop_user_srv?charsetutf8mb4parseTimeTruelocLocal// 设置全局的logger这个logger在我们执行每个sql语句的时候会打印每一行sqlnewLogger : logger.New(log.New(os.Stdout, \r\n, log.LstdFlags), // io writerlogger.Config{SlowThreshold: time.Second, // 慢 SQL 阈值LogLevel: logger.Info, // Log levelColorful: true, // 禁用彩色打印},)db, err : gorm.Open(mysql.Open(dsn), gorm.Config{// 表名NamingStrategy: schema.NamingStrategy{// 这里直接使用 model 名SingularTable: true,},Logger: newLogger,})if err ! nil {fmt.Println(err)}//定义一个表结构 将表结构直接生成对应的表 - migrations// 迁移 schema_ db.AutoMigrate(model.User{})// 写入一些数据options : password.Options{16, 100, 32, sha512.New}salt, encodedPwd : password.Encode(admin123, options)newPassword : fmt.Sprintf($pbkdf2-sha512$%s$%s, salt, encodedPwd)fmt.Println(newPassword)for i : 0; i 10; i {user : model.User{NickName: fmt.Sprintf(Roy%d, i),Mobile: fmt.Sprintf(1878222222%d, i),Password: newPassword,}db.Save(user)} }nacos 上定义配置本地配置文件定义 nacos 地址及需要的配置集信息即可// user-srv(dev) {name: user-srv,host: 192.168.0.102,port: 64924, // 用于开发环境tags: [Roy, shop, go],mysql: {db: shop_user_srv,host: 192.168.109.128,port: 3306,user: root,password: 123456},consul: {host: 192.168.109.128,port: 8500},env: SHOP_DEBUG }// user-web(dev) {name: user-web,host: 192.168.0.102, // 在我的Windows上启动tags:[shop, Roy, user, web],port: 8021,// 服务发现user_srv: {// 只需保留namename: user-srv},jwt: {key: 5$!UEmvB#nRBIwab#Sy!zofKEOGLRtE},sms: {key: ,secrect: ,expire: 300},redis: {host: 192.168.109.128,port: 6379},consul: {host: 192.168.109.128,port: 8500},env: SHOP_DEBUG }sms 相关的 key 登录自己的阿里云控制台获取redis 安装默认在 6379 端口新建环境变量SHOP_DEBUGtrue重启 GoLand 开发环境端口号固定生产环境随机获取 consul 配置 项目启动会自动注册的 我这里项目启动在 Windows 机器0.102 user-web 和 user-srv 项目都通过配置中心获取 ip/port定义 ip 主要为了 consul 注册定义端口主要是为了开发环境使用因为注册在 consul 的端口要看是 dev/pro生产环境中是动态的和这里配置的就不一样了目前新加service或者client服务器就要新加一份配置涉及到后期的集群管理和容灾MySQL、consul、nacos、redis、yapi 均启动在虚拟机109.128最终上线都要放在 Linux 服务器启动目前为了方便写代码采用这种方式 yapi 测试 这里是测试 APIuser-web部分要按照这个配置初始化部署成功后访问http://ip:3000/邮箱登录密码ymfe.orgyapi 底层用了 MongoDBnacos 底层用了 MySQL 导入定义了测试接口的 json 文件安装扩展解决跨域问题 设置请求参数并发送 yapi 可以严格规定请求参数和返回数据的格式也就是预览中的那份文档前后端必须严格遵从可以mock可以指定值 对于前端要严格传参带headeryapi相当于后端对于后端一定要返回指定格式类型就是数字字符串但格式很多的数据yapi相当于前端mock 地址固定不能换 IP因为是作为服务器的发起请求可以换 IP请求谁都可以 QA user-web 中能监听配置文件变化但好像没起作用如何监听 nacos 中心的配置变化呢换了热点服务端 IP 变了注册到 consul 异常 小结 这几篇和《PythonGo实践》的内容基本一致只是 Server 层用了 Go 语言实现而非 Python对一些细节和流程也做了补充强调有助于理解也显得废话较多基本定下了开发基调后续会快速开发完所有的微服务实现电商系统最后将重点放在 k8s 部署、单元测试、重构、调优
http://www.w-s-a.com/news/545998/

相关文章:

  • 怎么做垂直自营网站游戏咨询网站建设目标是什么
  • 建设网站需要给钱吗建立网站三大基础
  • 金融公司网站 htmlwordpress 防火墙
  • 重庆智能建站模板网站投票系统 js
  • 网站维护的内容和步骤网站做什么内容
  • 万网虚拟主机建网站wordpress协调世界时
  • 微网站建设方式应用大全网站
  • 网站速度测速织梦模板下载
  • 环保网站建设公司排名汉阴网站建设
  • 自己做网站的二维码wordpress用户权限在哪改
  • 网站使用说明书网站建设公司的介绍
  • 推广型网站免费建设网站防盗链设置
  • 建设银行网站查开户行网站反链暴增怎么回事
  • centos7做网站软件实施工程师工资一般多少
  • 专业房产网站建设深圳建设交易集团
  • 政务网站建设标准项目经理接到网站开发怎么开展
  • 网站框架设计好后怎么做网站广告销售怎们做
  • asp技校网站保定八大平台公司
  • wordpress网站前端优化网站备案批量查询
  • 北京企业做网站杭州seo中心
  • 护肤品网站建设前的行业分析wordpress电子书模板
  • 做网站怎么销售.net开发网站怎么样
  • 蚌埠网站优化网站换空间wordpress
  • 微网站开发框架公司企业logo
  • 大淘客官网做的网站打不开网站建设完成
  • 婚纱摄影网站模板让别人做网站怎样才安全
  • 技术支持 骏域网站建设专家佛山网站运营管理教材
  • 个体营业执照可以做网站服务吗电商运营学校培训
  • 企业网站免费推广的方法.wordpress 爱情模板下载地址
  • 轻淘客 轻网站怎么做手机开发人员选项怎么打开