Commit aa289c9c authored by zs's avatar zs
Browse files

规范代码

parent fbeb92c6
package api
import (
"git.zc0901.com/go/god/lib/service"
"time"
"git.zc0901.com/go/god/lib/service"
)
type (
// 私钥配置
// PrivateKeyConf 私钥配置
PrivateKeyConf struct {
Fingerprint string // 指纹配置
KeyFile string // 秘钥配置
}
// 签名配置
// SignatureConf 签名配置
SignatureConf struct {
Strict bool `json:",default=false"` // 签名是否为严格模式,若是则签名秘钥(PrivateKeys)必填
Expire time.Duration `json:",default=1h"` // 签名有效期,默认1小时
PrivateKeys []PrivateKeyConf // 签名秘钥相关配置
}
// 接口配置
// Conf 接口配置
//
// 为什么不命名为 Conf或Config,因为需要考虑如下用法:
//
// type Config struct {
// rpc.RpcConf
// api.ApiConf
// api.Conf
// }
//
// 所以如果命名为 Conf 的话,Config中就会有两个 Conf 了。
ApiConf struct {
service.ServiceConf // service 配置
Host string `json:",default=0.0.0.0"` // http 监听ip,默认0.0.0.0
Port int // http 监听端口,必填
CertFile string `json:",optional"` // http 证书文件,可选
KeyFile string `json:",optional"` // http 私钥文件,可选
Verbose bool `json:",optional"` // 是否打印详细http请求日志
MaxConns int `json:",default=10000"` // http同时可接受最大请求数(限流数),默认10000
MaxBytes int64 `json:",default=1048576,range=[0:33554432]"` // 最大文件上传大小(字节)默认1Mb,最大32Mb
Timeout int64 `json:",default=3000"` // 请求超时时间,默认3000毫秒
CpuThreshold int64 `json:",default=900,range=[0:1000]"` // cpu降载阈值,默认900,可选范围0-1000
Signature SignatureConf `json:",optional"` // 签名配置
Conf struct {
service.Conf // service 配置
Host string `json:",default=0.0.0.0"` // http 监听ip,默认0.0.0.0
Port int // http 监听端口,必填
CertFile string `json:",optional"` // http 证书文件,可选
KeyFile string `json:",optional"` // http 私钥文件,可选
Verbose bool `json:",optional"` // 是否打印详细http请求日志
MaxConns int `json:",default=10000"` // http同时可接受最大请求数(限流数),默认10000
MaxBytes int64 `json:",default=1048576,range=[0:33554432]"` // 最大文件上传大小(字节)默认1Mb,最大32Mb
Timeout int64 `json:",default=3000"` // 请求超时时间,默认3000毫秒
CpuThreshold int64 `json:",default=900,range=[0:1000]"` // cpu降载阈值,默认900,可选范围0-1000
Signature SignatureConf `json:",optional"` // 签名配置
}
)
......@@ -3,6 +3,9 @@ package api
import (
"errors"
"fmt"
"net/http"
"time"
"git.zc0901.com/go/god/api/handler"
"git.zc0901.com/go/god/api/internal"
"git.zc0901.com/go/god/api/router"
......@@ -10,8 +13,6 @@ import (
"git.zc0901.com/go/god/lib/load"
"git.zc0901.com/go/god/lib/stat"
"github.com/justinas/alice"
"net/http"
"time"
)
// 使用 1000m 来表示 cpu 负载为 100%
......@@ -21,7 +22,7 @@ var ErrSignatureConfig = errors.New("错误的签名配置")
// API 内部引擎
type engine struct {
conf ApiConf
conf Conf
routes []featuredRoutes
middlewares []Middleware
unauthorizedCallback handler.UnauthorizedCallback
......@@ -31,7 +32,7 @@ type engine struct {
}
// 新建 API 引擎
func newEngine(c ApiConf) *engine {
func newEngine(c Conf) *engine {
e := &engine{conf: c}
// 启用cpu负载均衡
......@@ -209,7 +210,7 @@ func (e *engine) getLogHandler() alice.Constructor {
}
}
// 获取负载均衡流器
// 获取负载均衡流器
func (e *engine) getShedder(priority bool) load.Shedder {
if priority && e.priorityShedder != nil {
return e.priorityShedder
......
......@@ -39,7 +39,7 @@ type (
AuthorizeOption func(opts *AuthorizeOptions)
)
// API JWT鉴权中间件
// Authorize API JWT鉴权中间件
func Authorize(secret string, opts ...AuthorizeOption) func(http.Handler) http.Handler {
var authOpts AuthorizeOptions
for _, opt := range opts {
......
......@@ -2,18 +2,19 @@ package handler
import (
"fmt"
"net/http"
"strings"
"git.zc0901.com/go/god/api/httpx"
"git.zc0901.com/go/god/api/internal/security"
"git.zc0901.com/go/god/lib/breaker"
"git.zc0901.com/go/god/lib/logx"
"git.zc0901.com/go/god/lib/stat"
"net/http"
"strings"
)
const breakerSeparator = "://"
// API 熔断器中间件
// BreakerHandler API 熔断器中间件
func BreakerHandler(method, path string, metrics *stat.Metrics) func(http.Handler) http.Handler {
brk := breaker.NewBreaker(breaker.WithName(strings.Join([]string{method, path}, breakerSeparator)))
return func(next http.Handler) http.Handler {
......
package handler
import (
"net/http"
"time"
"git.zc0901.com/go/god/api/httpx"
"git.zc0901.com/go/god/api/internal/security"
"git.zc0901.com/go/god/lib/codec"
"git.zc0901.com/go/god/lib/logx"
"net/http"
"time"
)
type UnsignedCallback func(w http.ResponseWriter, r *http.Request, next http.Handler, strict bool, code int) // 未签名回调函数
// API 参数签名中间件
// ContentSecurityHandler API 参数签名中间件
func ContentSecurityHandler(decrypters map[string]codec.RsaDecrypter, tolerance time.Duration, strict bool, callbacks ...UnsignedCallback) func(handler http.Handler) http.Handler {
if len(callbacks) == 0 {
callbacks = append(callbacks, handleVerificationFailure)
......
......@@ -5,19 +5,20 @@ import (
"bytes"
"encoding/base64"
"errors"
"git.zc0901.com/go/god/lib/codec"
"git.zc0901.com/go/god/lib/logx"
"io"
"io/ioutil"
"net"
"net/http"
"git.zc0901.com/go/god/lib/codec"
"git.zc0901.com/go/god/lib/logx"
)
const maxBytes = 1 << 20 // 1MB
var errContentLengthExceeded = errors.New("内容超出长度限制")
// API 加密响应中间件
// EncrpytedHandler API 加密响应中间件
// key: 解密秘钥
func EncrpytedHandler(key []byte) func(handler http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
......
......@@ -2,14 +2,15 @@ package handler
import (
"compress/gzip"
"git.zc0901.com/go/god/api/httpx"
"net/http"
"strings"
"git.zc0901.com/go/god/api/httpx"
)
const gzipEncoding = "gzip"
// API Gzip 中间件
// GzipHandler API Gzip 中间件
func GzipHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.Contains(r.Header.Get(httpx.ContentEncoding), gzipEncoding) {
......
......@@ -55,7 +55,7 @@ func (w *loggedResponseWriter) WriteHeader(code int) {
w.code = code
}
// API 日志记录中间件
// LogHandler API 日志记录中间件
func LogHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
timer := utils.NewElapsedTimer()
......@@ -74,7 +74,7 @@ func LogHandler(next http.Handler) http.Handler {
})
}
// API 详细日志记录中间件
// DetailedLogHandler API 详细日志记录中间件
func DetailedLogHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
timer := utils.NewElapsedTimer()
......
package handler
import (
"git.zc0901.com/go/god/api/internal"
"net/http"
"git.zc0901.com/go/god/api/internal"
)
// API 最大请求字节中间件
// MaxBytesHandler API 最大请求字节中间件
func MaxBytesHandler(max int64) func(http.Handler) http.Handler {
if max <= 0 {
return func(next http.Handler) http.Handler {
......
package handler
import (
"net/http"
"git.zc0901.com/go/god/api/internal"
"git.zc0901.com/go/god/lib/logx"
"git.zc0901.com/go/god/lib/syncx"
"net/http"
)
// API 最大请求连接数中间件
// MaxConns API 最大请求连接数中间件
func MaxConns(max int) func(http.Handler) http.Handler {
if max <= 0 {
return func(next http.Handler) http.Handler {
......
package handler
import (
"net/http"
"git.zc0901.com/go/god/lib/stat"
"git.zc0901.com/go/god/lib/timex"
"net/http"
)
// API 耗时监控中间件
// MetricHandler API 耗时监控中间件
func MetricHandler(metrics *stat.Metrics) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
......
......@@ -2,12 +2,13 @@ package handler
import (
"fmt"
"git.zc0901.com/go/god/api/internal"
"net/http"
"runtime/debug"
"git.zc0901.com/go/god/api/internal"
)
// API 异常捕获中间件
// RecoverHandler API 异常捕获中间件
func RecoverHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
......
package handler
import (
"net/http"
"sync"
"git.zc0901.com/go/god/api/httpx"
"git.zc0901.com/go/god/api/internal/security"
"git.zc0901.com/go/god/lib/load"
"git.zc0901.com/go/god/lib/logx"
"git.zc0901.com/go/god/lib/stat"
"net/http"
"sync"
)
const serviceType = "api"
const serviceType = "API"
var (
shedderStat *load.ShedderStat
lock sync.Mutex
)
// API 负载均衡中间件
// ShedderHandler API 负载泄流中间件
func ShedderHandler(shedder load.Shedder, metrics *stat.Metrics) func(http.Handler) http.Handler {
if shedder == nil {
return func(next http.Handler) http.Handler {
......
......@@ -5,15 +5,14 @@ import (
"time"
)
const reason = "请求超时"
const reason = "API 请求超时"
// API 超时处理中间件
// TimeoutHandler API 超时处理中间件
func TimeoutHandler(duration time.Duration) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
if duration > 0 {
return http.TimeoutHandler(next, duration, reason)
} else {
return next
}
return next
}
}
package handler
import (
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func init() {
log.SetOutput(ioutil.Discard)
}
func TestTimeout(t *testing.T) {
timeoutHandler := TimeoutHandler(time.Millisecond)
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Minute)
}))
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
resp := httptest.NewRecorder()
handler.ServeHTTP(resp, req)
assert.Equal(t, http.StatusServiceUnavailable, resp.Code)
}
func TestWithinTimeout(t *testing.T) {
timeoutHandler := TimeoutHandler(time.Second)
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Millisecond)
}))
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
resp := httptest.NewRecorder()
handler.ServeHTTP(resp, req)
assert.Equal(t, http.StatusOK, resp.Code)
}
func TestWithoutTimeout(t *testing.T) {
timeoutHandler := TimeoutHandler(0)
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(100 * time.Millisecond)
}))
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
resp := httptest.NewRecorder()
handler.ServeHTTP(resp, req)
assert.Equal(t, http.StatusOK, resp.Code)
}
package handler
import (
"net/http"
"git.zc0901.com/go/god/lib/logx"
"git.zc0901.com/go/god/lib/sysx"
"git.zc0901.com/go/god/lib/trace"
"net/http"
)
// API 链路跟踪中间件
// TraceHandler API 链路跟踪中间件
func TraceHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// **1** 拦截请求,获取 header 中的traceId信息
......
......@@ -2,9 +2,10 @@ package httpx
import (
"encoding/json"
"git.zc0901.com/go/god/lib/logx"
"net/http"
"sync"
"git.zc0901.com/go/god/lib/logx"
)
var (
......@@ -13,7 +14,25 @@ var (
lock sync.RWMutex
)
// 错误响应,支持自定义错误处理器
type Message struct {
Code int `json:"code"`
Data interface{} `json:"data"`
Msg string `json:"message"`
}
func (e *Message) Error() string {
return e.Msg
}
func NewCodeError(code int, msg string) error {
return &Message{Code: code, Msg: msg}
}
func NewDefaultError(msg string) error {
return NewCodeError(0, msg)
}
// Error 错误响应,支持自定义错误处理器
func Error(w http.ResponseWriter, err error) {
lock.RLock()
handler := errorHandler
......@@ -29,16 +48,22 @@ func Error(w http.ResponseWriter, err error) {
if ok {
http.Error(w, e.Error(), code)
} else {
if m, ok := body.(Message); ok {
if m.Code > 0 {
http.Error(w, m.Msg, http.StatusOK)
return
}
}
WriteJson(w, code, body)
}
}
// 正常响应
// Ok 正常响应
func Ok(w http.ResponseWriter) {
w.WriteHeader(http.StatusOK)
}
// 正常JSON响应
// OkJson 正常JSON响应
func OkJson(w http.ResponseWriter, body interface{}) {
lock.RLock()
handler := okJsonHandler
......@@ -52,21 +77,21 @@ func OkJson(w http.ResponseWriter, body interface{}) {
return
}
// 设置自定义错误处理器
// SetErrorHandler 设置自定义错误处理器
func SetErrorHandler(handler func(error) (int, interface{})) {
lock.Lock()
defer lock.Unlock()
errorHandler = handler
}
// 设置自定义成功处理器
// SetOkJsonHandler 设置自定义成功处理器
func SetOkJsonHandler(handler func(body interface{}) interface{}) {
lock.Lock()
defer lock.Unlock()
okJsonHandler = handler
}
// 写JSON响应
// WriteJson 写JSON响应
func WriteJson(w http.ResponseWriter, code int, body interface{}) {
w.Header().Set(ContentType, ApplicationJson)
w.WriteHeader(code)
......
......@@ -2,11 +2,12 @@ package api
import (
"errors"
"log"
"net/http"
"git.zc0901.com/go/god/api/handler"
"git.zc0901.com/go/god/api/router"
"git.zc0901.com/go/god/lib/logx"
"log"
"net/http"
)
type (
......@@ -22,7 +23,7 @@ type (
}
)
func MustNewServer(c ApiConf, opts ...RunOption) *Server {
func MustNewServer(c Conf, opts ...RunOption) *Server {
server, err := NewServer(c, opts...)
if err != nil {
log.Fatal(err)
......@@ -31,7 +32,7 @@ func MustNewServer(c ApiConf, opts ...RunOption) *Server {
return server
}
func NewServer(c ApiConf, opts ...RunOption) (*Server, error) {
func NewServer(c Conf, opts ...RunOption) (*Server, error) {
if len(opts) > 1 {
return nil, errors.New("只允许一个 RunOption")
}
......
......@@ -2,10 +2,11 @@ package main
import (
"flag"
"net/http"
"git.zc0901.com/go/god/api"
"git.zc0901.com/go/god/api/httpx"
"git.zc0901.com/go/god/lib/conf"
"net/http"
)
var configFile = flag.String("f", "config.yaml", "API 配置文件")
......@@ -13,7 +14,7 @@ var configFile = flag.String("f", "config.yaml", "API 配置文件")
func main() {
// 读取配置文件
flag.Parse()
var c api.ApiConf
var c api.Conf
conf.MustLoad(*configFile, &c)
// 新建 API 服务器
......
package main
import (
"net/http"
"runtime"
"time"
"git.zc0901.com/go/god/api"
"git.zc0901.com/go/god/lib/logx"
"git.zc0901.com/go/god/lib/service"
"git.zc0901.com/go/god/lib/stat"
"git.zc0901.com/go/god/lib/syncx"
"net/http"
"runtime"
"time"
)
func main() {
logx.Disable()
stat.SetReporter(nil)
server := api.MustNewServer(api.ApiConf{
ServiceConf: service.ServiceConf{
server := api.MustNewServer(api.Conf{
ServiceConf: service.Conf{
Name: "api breaker",
Log: logx.LogConf{Mode: "console"},
},
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment