在实际开发中,需要前后端需要协商状态码,状态码用于后端返前端时使用。在一个团队中,定义的状态码讲道理应该是一致的,项目开始的起始阶段状态码应该是定义了个七七八八的,随着功能的叠加而不断增加。此系列将围绕我的研发之旅进行。

状态码推荐的项目目录为pkg/globalcode目录

后端返前端的json 格式为:

{
"code": 状态码,
"data": [
功能逻辑后返前字段
],
"message": 状态码对应的message
}

本片将以成功参数校验两个常见的状态码为案例进行

自定义状态码 目录结构

.
├── [ 96] cmd
│   └── [1.3K] root.go
├── [ 128] config
│   ├── [2.2K] cfg.go
│   └── [ 129] config.yaml
├── [ 160] controller
│   ├── [ 267] base.go
│   ├── [ 452] name.go
│   └── [ 96] validation # 校验层
│   └── [ 151] name.go
├── [ 242] go.mod
├── [ 66K] go.sum
├── [ 200] main.go
├── [ 96] pkg
│   └── [ 128] globalcode
│   ├── [ 79] code.go
│   └── [ 148] message.go
├── [ 96] routes
│   └── [ 343] routes.go
├── [ 96] routes
│   └── [ 343] routes.go
└── [ 96] service
└──[ 80] name.go 8 directories, 13 files

逻辑:项目初始化 --> 前端调接口--> 后端routes层 --> 后端controller层(判断前端传参是否有无(如果没有前端传参跳过此步骤) )--> 后端service层处理功能逻辑(有可能需要model层) --> 后端controller层处理返回结果(这里需要状态码处理)

项目初始化

main.go

/**
* @Author: zisefeizhu
* @Description: code
* @File: main.go
* @Version: 1.0.0
* @Date: 2021/9/4 10:13
*/ package main import (
"codedemo/cmd"
) func main() {
//入口
cmd.Execute()
}

cmd/root.go

package cmd

import (
"codedemo/config"
"codedemo/routes"
"fmt"
"os" "github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
) var (
cfgFile string
serverPort int
) var rootCmd = &cobra.Command{
Use: "server",
Short: "about the code",
Long: "summary of status codes from zisefeizhu",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("启动参数: ", args)
httpServer()
},
} func init() {
logrus.Infoln("init root.go...")
cobra.OnInitialize(initConifg)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $CURRENT_DIR/config/config.yaml)")
rootCmd.Flags().IntVarP(&serverPort, "port", "p", 9001, "port on which the server will listen")
} // 初始化配置
func initConifg() {
config.Loader(cfgFile)
config.InitLog()
} func httpServer() {
logrus.Infoln("server start...")
defer func() {
logrus.Infoln("server exit..")
}()
//设置模式,设置模式要放在调用Default()函数之前
gin.SetMode(viper.GetString("runmode"))
logrus.Infoln("runmode: ", viper.GetString("runmode")) // 路由设置
g := gin.Default()
routes.Init(g)
g.Run(fmt.Sprintf(":%d", serverPort)) } // Execute rootCmd
func Execute() {
if err := rootCmd.Execute(); err != nil {
logrus.Fatalln(err)
os.Exit(1)
}
}

config/cfg.go

package config

import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"io"
"os"
"path/filepath"
"strings"
) // Loader 加载配置文件
func Loader(cfgFile string) {
if cfgFile == "" {
path, _ := os.Getwd()
cfgFile = path + "/config/config.yaml"
fmt.Println(cfgFile)
} viper.SetConfigFile(cfgFile) //用来指定配置文件的名称
viper.SetEnvPrefix("ENV") //SetEnvPrefix会设置一个环境变量的前缀名
viper.AutomaticEnv() //会获取所有的环境变量,同时如果设置过了前缀则会自动补全前缀名
replacer := strings.NewReplacer(".", "_") //NewReplacer() 使用提供的多组old、new字符串对创建并返回一个*Replacer
viper.SetEnvKeyReplacer(replacer) if err := viper.ReadInConfig(); err != nil {
fmt.Printf("config file error: %s\n", err)
os.Exit(1)
}
} // InitLog 初始化日志
func InitLog() {
// log.logrus_json
if viper.GetBool("log.logrus_json") {
logrus.SetFormatter(&logrus.JSONFormatter{})
} // log.logrus_level
switch viper.GetString("log.logrus_level") {
case "trace":
logrus.SetLevel(logrus.TraceLevel)
case "debug":
logrus.SetLevel(logrus.DebugLevel)
case "info":
logrus.SetLevel(logrus.InfoLevel)
case "warn":
logrus.SetLevel(logrus.WarnLevel)
case "error":
logrus.SetLevel(logrus.ErrorLevel)
} // log.logrus_file
if viper.GetBool("log.file") {
logrusFile := viper.GetString("log.logrus_file")
os.MkdirAll(filepath.Dir(logrusFile), os.ModePerm) file, err := os.OpenFile(logrusFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err == nil {
if viper.GetBool("log.logrus_console") {
logrus.SetOutput(io.MultiWriter(file, os.Stdout))
} else {
logrus.SetOutput(file)
}
} // log.gin_file & log.gin_console
ginFile := viper.GetString("log.gin_file")
os.MkdirAll(filepath.Dir(ginFile), os.ModePerm) file, err = os.OpenFile(ginFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err == nil {
if viper.GetBool("log.gin_console") {
gin.DefaultWriter = io.MultiWriter(file, os.Stdout)
} else {
gin.DefaultWriter = io.MultiWriter(file)
}
}
} // default
logrus.SetReportCaller(true)
}

config/config.yaml

prefix_path: /zisefeizhu/api/v1 #api路径
gormlog: true # gorm 的日志模式, true 是详细日志, false 不记录日志

routes层

routes.go

package routes

import (
"codedemo/controller"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/spf13/viper"
) func Init(g *gin.Engine) {
prefixPath := viper.GetString("prefix_path")
g.Use(cors.Default())
// 集群
codedemo := g.Group(prefixPath + "/code")
{
codedemo.GET("/codedemo",controller.GetName)
}
}

controller 层

name.go

package controller

import (
"codedemo/controller/validation"
"codedemo/pkg/globalcode"
"codedemo/service"
"github.com/gin-gonic/gin"
"strings"
) func GetName(c *gin.Context)() {
var param validation.GetNameRepos
if err := c.ShouldBind(&param); err != nil {
Response(c, globalcode.PARAMETER_ERR, err.Error())
return
}
param.Name = strings.TrimSpace(param.Name)
if param.Name == "zise" {
name := service.CodeDemo(param.Name)
Response(c, globalcode.SUCCESS ,name)
} else {
// 模仿自定义状态码然后返回前端
}
}

validation/name.go

package validation

// GetNameRepos 前端param
type GetNameRepos struct {
Name string `json:"name" form:"name" binding:"required"` // 姓名不能为空
}

base.go

package controller

import (
"codedemo/pkg/globalcode"
"github.com/gin-gonic/gin"
"net/http"
) func Response(c *gin.Context, code int, data interface{}) {
c.JSON(http.StatusOK, gin.H{
"code": code,
"message": globalcode.Msg[code],
"data": data,
})
}

service 层

name.go

package service

func CodeDemo(name string)  string {
return name + "feizhu"
}

pkg/globalcode 层

  • 状态码处理,本篇的重心

code.go

  • 定义状态码
package globalcode

var (
SUCCESS = 200
PARAMETER_ERR = 10000
)

message.go

  • 状态码对应的信息
package globalcode

// Msg 全局状态码
var Msg = map[int]string{
SUCCESS: "请求成功",
PARAMETER_ERR: "请求参数错误",

验证

    1. 错误code

    1. 正确code

紫色飞猪的研发之旅--06go自定义状态码的更多相关文章

  1. 飞猪基于 Serverless 的云+端实践与思考

    作者 | 王恒飞(承荫) 本文整理自飞猪旅行前端技术专家--王恒飞(承荫)在[阿里云 Serverless Developer Meetup 上海站]上的分享.点击查看直播回放:https://dev ...

  2. 对飞猪H5端API接口sign签名逆向实验

    免责声明 本文章所提到的技术仅用于学习用途,禁止使用本文章的任何技术进行发起网络攻击.非法利用等网络犯罪行为,一切信息禁止用于任何非法用途.若读者利用文章所提到的技术实施违法犯罪行为,其责任一概由读者 ...

  3. 不二之选_iTOP-4418开发板研发之旅_缩短开发时间

    迅为iTOP-4418开发板拿到手?用能力印证梦想,培养你的研发路程,能力·思维 一.板载WIFI蓝牙.4G.GPS.千兆以太网接口.串口.重力加速度计等. 二.自选模块支持500W摄像头自动对焦摄像 ...

  4. 我的Android进阶之旅------>Android自定义View来实现解析lrc歌词并同步滚动、上下拖动、缩放歌词的功能

    前言 一LRC歌词文件简介 1什么是LRC歌词文件 2LRC歌词文件的格式 LRC歌词文件的标签类型 1标识标签 2时间标签 二解析LRC歌词 1读取出歌词文件 2解析得到的歌词内容 1表示每行歌词内 ...

  5. 告别IT,出售多年自己研发的股票分析系统源码

    不知已过而立,发狠告别IT,回头看看以前自己的多个作品,耗时最多的就是这个股票分析系统了,留在自己的电脑里也体现不出多大价值了,故打算出售源码给需要的人,联系方式QQ:874724605 注明:股票源 ...

  6. K/3 Cloud开发之旅 -- 主页自定义篇(一)

    如果说我们要进行主页自定义篇,首先涉及到的就是登陆的自定义,那么如何进行登录界面的自定义呢 其实登陆界面自定义主要就是图片的替换 ,那么我们就看下登陆界面的图片的组成 登录页面底图有两部分组成,一个是 ...

  7. [原创] zabbix学习之旅一:源码安装

    zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案.zabbix能监视各种网络参数,保证服务器系统的安全运营:并提供灵活的通知机制以让系统管理员快速定位/解决存 ...

  8. 我的Android进阶之旅------>Android自定义View实现带数字的进度条(NumberProgressBar)

    今天在Github上面看到一个来自于 daimajia所写的关于Android自定义View实现带数字的进度条(NumberProgressBar)的精彩案例,在这里分享给大家一起来学习学习!同时感谢 ...

  9. 我的Android进阶之旅------>Android自定义窗口标题实例

    该实例的功能比较简单,但是通过该实例的扩展可以在自定义标题中做出菜单导航等实用的功能,为了实现自定义窗口标题,需要做以下几个步骤: 1.给自定义标题提供一个界面 2.将自定义标题应用给Activity ...

随机推荐

  1. 01MATLAB导论

    MATLAB语言的主要功能 数值计算 符号计算 图形绘制 程序流程控制 工具箱 课程的学习目标 要求理解MATLAB功能实现的数学背景与算法原理 掌握利用MATLAB进行问题求解的基本规律 能够利用M ...

  2. 构建前端第13篇之---VUE的method:{}的括号未括到方法导致 _vm.linkProps is not a function

  3. JS对DOM的操作优化法则

    html页面显示过程 解析HTML,并生成一棵DOM tree 解析各种样式并结合DOM tree生成一棵Render tree 对Render tree的各个节点计算布局信息,比如box的位置与尺寸 ...

  4. Python实用案例,Python脚本,Python实现帮你选择双色球号码

    往期回顾 Python实现自动监测Github项目并打开网页 Python实现文件自动归类 前言: 今天我们就利用python脚本实现帮你选择双色球号码.直接开整~ 开发工具: python版本: 3 ...

  5. joomla 3.7.0 (CVE-2017-8917) SQL注入漏洞

    影响版本: 3.7.0 poc http://192.168.49.2:8080/index.php?option=com_fields&view=fields&layout=moda ...

  6. XSS challenges靶机

    第一关 <script>alert(123)</script> "><svg onload=alert(123)> 第二关 <script&g ...

  7. 大数据学习(26)—— Spark之RDD

    做大数据一定要有一个概念,需要处理的数据量非常大,少则几十T,多则上百P,全部放内存是不可能的,会OOM,必须要用迭代器一条一条处理. RDD叫做弹性分布式数据集,是早期Spark最核心的概念,是一种 ...

  8. 腾讯云TDSQL监控库密码忘记问题解决实战

    首先,给大家介绍一下TDSQL.TDSQL MySQL 版(TDSQL for MySQL)是腾讯打造的一款分布式数据库产品,具备强一致高可用.全球部署架构.分布式水平扩展.高性能.企业级安全等特性, ...

  9. 【Android面试查漏补缺】之Handler详解,带你全面理解Handler消息机制

    在安卓面试中,关于 Handler 的问题是必备的,但是这些关于 Handler 的知识点你都知道吗? 一.题目层次 Handler 的基本原理 子线程中怎么使用 Handler MessageQue ...

  10. 用VirtualBox搭建虚拟局域网

    用 Oracle VM VirtualBox 安装虚拟机,我在Windows 7上安装了ubuntu 11.10和xubuntu12.04两个虚拟机: 将这两个虚拟机的"网络"属性 ...