In order to facilitate the front-end page of the blog to deal with the request error of the back-end interface, we need to deal with the error result of the server. If the unified interface error normalization process is not carried out, there are many different interface error results, which will lead to the front-end error result processing becomes extremely tedious.
Interface response error handling
First, standardize the errcode error code
0," request successful "20001," server error" 20002," parameter error "20003," unable to find" 20004," Request too frequent "20005," Authentication failed, unable to find corresponding permission" 20006," authentication failed, Token error "20007," authentication failed, Token timeout "20008," Authentication failed, Token generation failed"Copy the code
Create base_code.go under PKG /errcode
package errcode
var (
Success = NewError(0."Request successful")
ServerError = NewError(20001."Server error")
InvalidParams = NewError(20002."Parameter error")
NotFound = NewError(20003."Can't find it.")
TooManyRequests = NewError(20004."Too many requests")
UnauthorizedAuthNotExist = NewError(20005."Authentication failed, cannot find corresponding permission")
UnauthorizedTokenError = NewError(20006 ,"Authentication failed, Token error")
UnauthorizedTokenTimeout = NewError(20007."Authentication failed, Token timed out")
UnauthorizedTokenGeneration = NewError(20008 ,"Authentication failed, Token generation failed"))Copy the code
Then we create our Error structure and method
Create errcode.go under PKG/errCode
package errcode
import (
"fmt"
"net/http"
)
type Error struct {
code int `json:"code"`
msg string `json:"msg"`
details []string `json:"details"`
}
var codes = map[int]string{}
func NewError(code int, msg string) *Error {
if _, ok := codes[code]; ok {
panic(fmt.Sprintf("Error code %d already exists, please change it.", code))
}
codes[code] = msg
return &Error{code:code, msg:msg}
}
func (e *Error) Error(a) string {
return fmt.Sprintf("Error code: %d, error message: %s", e.code, e.msg)
}
func (e *Error) Code(a) int {
return e.code
}
func (e *Error) Msg(a) string {
return e.msg
}
func (e *Error) Msgf(args []interface{}) string {
return fmt.Sprintf(e.msg, args...)
}
func (e *Error) Details(a) []string {
return e.details
}
func (e *Error) WithDetails(details ...string) *Error {
newError := *e
newError.details = []string{}
for _, d := range details {
newError.details = append(newError.details, d)
}
return &newError
}
func (e *Error) StatusCode(a) int {
switch e.Code() {
case Success.Code():
return http.StatusOK
case ServerError.Code():
return http.StatusInternalServerError
case InvalidParams.Code():
return http.StatusBadRequest
case NotFound.Code():
return http.StatusNotFound
case TooManyRequests.Code():
return http.StatusTooManyRequests
case UnauthorizedAuthNotExist.Code():
fallthrough
case UnauthorizedTokenError.Code():
fallthrough
case UnauthorizedTokenTimeout.Code():
fallthrough
case UnauthorizedTokenGeneration.Code():
return http.StatusUnauthorized
}
return http.StatusInternalServerError
}
Copy the code
Then we’ll use our Error structure for interface processing
Use Viper to manage our configuration
Viper is a complete configuration solution for Go applications that is designed to work within applications and handle all types of configuration requirements and formats. It supports.
-
Setting defaults
-
Read configuration files for JSON, TOML, YAML, HCL, envFile, and Java properties
-
Viewing and rereading configuration files in real time (optional)
-
Read from an environment variable
-
Read from a remote configuration system (ETCD or Consul) and watch for changes
-
Read from the command line flag
-
Read from buffer
-
Set explicit values
Viper can be thought of as a registry for all your application configuration needs.
Github github.com/spf13/viper
Viper installation
go get github.com/spf13/viper
Copy the code
Create config.yaml under /configs
Server:
RunMode: debug
HttpPort: 8080
ReadTimeout: 60
WriteTimeout: 60
App:
DefaultPageSize: 10 The default page display number
MaxPageSize: 100 # Maximum number of pages to display
LogSavePath: storage/logs
LogFileName: app
LogFileExt: .log # Extension of log output file
Database:
DBType: mysql # database type
Username: root Mysql user name
Password: root # mysql password
Host: 127.0. 01.: 3306 Mysql > connect to mysql
DBName: go_server_mysqldb Mysql database name
TablePrefix: blog_ # table prefix
Charset: utf8 The # character set
ParseTime: True The query result is automatically parsed to time
MaxIdleConns: 10 The maximum number of free connections in Mysql is 2
MaxOpenConns: 30 Mysql > set maximum number of connections
Copy the code
Setting. Go initializes our viper under/PKG /setting
package setting
import "github.com/spf13/viper"
type Setting struct {
vp *viper.Viper
}
func NewSetting(a) (*Setting, error) {
// Create a viper instance
vp := viper.New()
// Set the configuration name
vp.SetConfigName("config")
// Add the configuration file directory
vp.AddConfigPath("configs/")
// Specify the configuration file format
vp.SetConfigType("yaml")
// Read the configuration file
err := vp.ReadInConfig()
iferr ! =nil {
return nil, err
}
// The output of the read configuration file can be omitted
err = vp.SafeWriteConfigAs("configs/output.yaml")
iferr ! =nil {
return nil, err
}
/ / returns the setting
return &Setting{vp}, nil
}
Copy the code
Create section. Go under/PKG /setting to create our file configuration block field structure and method
package setting
import "time"
type ServerSettings struct {
RunMode string
HttpPort string
ReadTimeout time.Duration
WriteTimeout time.Duration
}
type AppSettings struct {
DefaultPageSize int
MaxPageSize int
LogSavePath string
LogFileName string
LogFileExt string
}
type DatabaseSettings struct{
DBType string
UserName string
Password string
Host string
DBName string
TablePrefix string
Charset string
ParseTime bool
MaxIdleConns int
MaxOpenConns int
}
// ReadSection Reads configuration section information
func (s *Setting) ReadSection(k string, v interface{}) error{
/* You also have the option of Unmarshalling all or a specific value to a struct, map, etc. There are two methods to do this: Unmarshal(rawVal interface{}) : error UnmarshalKey(key string, rawVal interface{}) : error */
// Deconstruct the configuration file information group
err := s.vp.UnmarshalKey(k,v)
iferr ! =nil {
return err
}
return nil
}
Copy the code
Create our global configuration manager under /golabl and create setting.go
package global
import "go-blog-server/pkg/setting"
var (
ServerSetting *setting.ServerSettings
AppSetting *setting.AppSettings
DatabaseSetting *setting.DatabaseSettings
)
Copy the code
Finally, change our main.go
package main
import (
"fmt"
"go-blog-server/global"
"go-blog-server/internal/routers"
"go-blog-server/pkg/setting"
"log"
"net/http"
"time"
)
// Call the go initializer
func init(a) {
// Install configuration
err := setupSetting()
iferr ! =nil {
log.Fatalf("init setupSetting Error : %v",err)
}
}
func main(a) {
// Instantiate the route handler
router := routers.NewRouter()
// Customize the HTTP Server
s := &http.Server {
// Set the listening port
Addr : ":" + global.ServerSetting.HttpPort,
// Add the handler we wrote
Handler: router,
// Sets the maximum time allowed to read and write
ReadTimeout : global.ServerSetting.ReadTimeout,
WriteTimeout : global.ServerSetting.WriteTimeout,
// set the maximum number of bytes in the request header to 2^20bytes 1Mb
MaxHeaderBytes: 1<<20,
}
err := s.ListenAndServe()
iferr ! =nil {
fmt.Println(err)
}
}
//setupSetting
func setupSetting(a) error{
mySetting,err := setting.NewSetting()
iferr ! =nil {
return err
}
err = mySetting.ReadSection("Server",&global.ServerSetting)
iferr ! =nil {
return err
}
err = mySetting.ReadSection("App", &global.AppSetting)
iferr ! =nil {
return err
}
err = mySetting.ReadSection("Database",&global.DatabaseSetting)
iferr ! =nil {
return err
}
// Set the data to seconds
global.ServerSetting.ReadTimeout *= time.Second
global.ServerSetting.WriteTimeout *= time.Second
return nil
}
Copy the code