wtf

package module
v4.2.5+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2020 License: LGPL-3.0 Imports: 21 Imported by: 0

README

go_wtf

各位看官,不要想歪了,WTF 是指小型的Web框架:Web Tiny Framework

4.0和之前版本的变动说明

  • 4.0和之前的变更是不兼容的,具体在于所有的组件都接口化了,即都可以用自己的实现来替换,也可以单独拿出去用。
  • 取消了对结构体Handle的支持,即从4.0开始,只支持Handle函数了,如果需要Handle一个结构体,请自行封装,很简单的。
  • 实现复杂Midware更简单了,定义Midware的实现,可以完成大部分工作,再修改其中Context的WriterWrapper,可以完成绝大部分工作,至于还有没有更复杂需求的,只能说我目前还没遇到过,如果有更过分需求的,可以提出来大家研究研究。

快速上手

  • 一个最简单的例子:
package main

import (
    "github.com/i11cn/go_wtf"
    "net/http"
)

func main() {
    serv := wtf.NewServer()
    serv.Handle(func(resp wtf.Response){
        resp.WriteString("点啥都是这一页")
    }, "/*")
    http.ListenAndServe(":4321", serv)
}
  • 一个稍微复杂点的例子:
package main

import (
    "github.com/i11cn/go_wtf"
    "net/http"
)

type (
    my_server struct {
    }
)

func (s *my_server) Hello(rest wtf.Rest, resp wtf.Response) {
    who := rest.Get("who")
    resp.WriteString("Hello," + who)
}

func main() {
    serv := wtf.NewServer()
    my := &my_server{}
    serv.Handle(func(rest wtf.Rest, resp wtf.Response) {
        my.Hello(rest, resp)
    }, "/hello/:who")
    serv.Handle(func(resp wtf.Response){
        resp.WriteString("点啥都是这一页")
    }, "/*")
    http.ListenAndServe(":4321", serv)
}

重点来了

WTF有一套非常灵活的路由规则(而且这个路由还可以独立创建,改吧改吧就能给其他框架用),这就要重点对路由进行说明

  • 支持其他路由的通配符格式

例如路由: "/user/:uid" 这样的格式,将会匹配uri: "/user/i11cn"、"/usr/who"、"/user/1234" 等等...

看代码:

func Hello(ctx wtf.Context) {
    who := ctx.RESTParams().Get("uid")
    ctx.WriteString("Hello," + who)
}

.
.
.

serv.Handle(Hello, "/user/:uid")

从这个例子里,也能看到如果要获取RESTful接口中url里的参数,是怎么操作的了:Context.RESTParams()

  • 支持正则表达式

从上面那个例子可以看出,对于参数uid,没有办法限定到底是字符串、数字、或是其他,如果还有这种需求,可以考虑用正则表达式来限定,正则表达式完全采用golang自己的regexp里的格式

例如路由: "/user/(?P<uid>\\d+)",将会只匹配 "/user/1234",而 "/user/i11cn"、"/user/who" 等包含非数字的uri不会被匹配到

看代码:

func Hello(ctx wtf.Context) {
    who := ctx.RESTParams().Get("uid")
    ctx.WriteString("Hello," + who)
}

.
.
.

serv.Handle(Hello, "/user/(?P<uid>\\d+))")
  • 通配符匹配

如果想匹配任意内容,可以用星号 '*' 来代替,不过需要注意的是,在模式中,'*' 之后的内容会被忽略,也就是说 "/user/*" 和 "/user/*/else" 是一样的,之后的 "/else" 被忽略掉了

另外需要注意的是,'*' 在匹配顺序中,是排在最后的,即如果前面没有任何路由匹配到,才会最后匹配到 '*'

  • 匹配顺序

如果匹配列表里,即有纯字符串式的完全匹配模式,又有正则表达式(或者其他路由的那种名称匹配),还有通配符模式,那么他们的匹配顺序是怎样的?举一个小栗子,各位看官就应该明白了:

serv.Handle(func(resp wtf.Response){
    resp.WriteString("任何字符,除了 9999")
}, "/user/:id") // 能够匹配 /user/who,除了 /user/9999

serv.Handle(func(resp wtf.Response){
    resp.WriteString("9999")
}, "/user/9999") // 匹配 /user/9999,其他都不匹配

serv.Handle(func(resp wtf.Response){
    resp.WriteString("很高兴的告诉大家,现在已经可以匹配啦,分开了正则和命名的方式,调整了优先级")
}, "/user/(?P<id>\\d+)") // 匹配 /user/1234 等全数字的路径,除了/user/9999

serv.Handle(func(resp wtf.Response){
    resp.WriteString("/user/* 是没戏了,只能搞定 /user/*/... 这样的了")
}, "/user/*") // 匹配不到任何url,因为都被 /user/:id 截胡了

serv.Handle(func(resp wtf.Response){
    resp.WriteString("所有以上搞不定的,都在这里")
}, "/*") // 除了/user/... 之外,任何url都能匹配

好了,详细解释一下

:id 这样的格式能够匹配完整的一级,所以 "/user/:id" 将会匹配所有 "/user"的下一级url,当然如果还有第三级目录, "/user/:id" 就无能为力了

如果有多个正则表达式(例如有 "/user/(?P\d+)" 和 "/user/(?P.+)",会逐个匹配,先匹配到的就会直接处理,不会再向后继续匹配了,所以各位亲,一定要注意,多个正则表达式的模式,匹配范围小的一定要写在前面啊

:id 这样的模式在所有正则表达式匹配完后才会匹配,因此如果正则表达式匹配内容和 :id 这样的相同,:id 就废了

"/user/*" 能够匹配所有以 "/user/" 开头的url,不过由于有两级的url全被 "/user/:id" 吸走了,所以它只能匹配三级url了,即在这里等同于 "/user/.../*"

特别的,有一个不包含正则的完全匹配模式 "/user/9999" , 嗯,这一类模式的优先级是最高的,所以完全忽视 "/user/:id" 的存在

小结一下匹配顺序: 完全匹配(不包含正则表达式的模式) > 正则表达式模式(注意匹配范围,小的写在前面,大的写在后面) > 命名模式 > 通配符 *

另有个小问题,如果*匹配到的内容,咋拿到呢?呃...两个办法哈,用GetIndex可以拿到,要不然,就给它起个名字吧:

serv.Handle(func(rest wtf.Rest){
    rest.GetIndex(1) // 第0个是 uid,第1个是 info
    rest.Get("info")
}, "/user/:uid/:info")

RESTful里的Method

大家都知道,RESTful很看重Method,不同的Method需要能够交给不同的方法处理,可是上面的路由里都没写Method,没这功能?NO NO NO,这么重要的功能怎么可能漏掉呢

serv.Handle(func(resp wtf.Response){
    resp.WriteString("这是GET方法来的")
}, "/*", "geT")

serv.Handle(func(req wtf.Request, resp wtf.Response){
    resp.WriteString(req.Method())
}, "/*", "post", "PUT")

serv.Handle(func(req wtf.Request, resp wtf.Response){
    resp.WriteString(req.Method())
}, "/user/:id", "all")

看代码,说故事,增加方法好像很简单,是吧

首先能感觉到的,是忽略大小写,geT和GET、get是同样的效果

再有,如果想匹配所有方法,就写个"all"好了,或者更简单一点,啥都不写...

但是注意,这些Method不要拼错了,因为这里的参数,同时支持vhost,或许不正确的Method会被当成vhost,那就糗大了...

关于Handle方法

以上重点说了RESTful的匹配规则等,这里需要再提一下匹配过后的处理方法(简称Handler)。WTF对于Handler的定义非常的随意,可以说都没什么限制了。通常友军们对于Handler的定义都类似这样: func(ctx Context) ,而我们,是这样滴 func (args ...interface{})

眼晕么?这什么意思?这句话的意思是说,以下这样的代码,是合理合法,完全正确的:

func dosomething(req wtf.Request, resp wtf.Response, mongo *mgo.Session) {
    ...
}

...

server.Handle(dosomething, "/dosomething", "GET", "localhost", "POST")
...

就这一段代码解释一下吧,首先定义了一个Handler函数 func dosomething(req wtf.Request, resp wtf.Response, mongo *mgo.Session),参数中并没有通常的Context,而是Request, Response, 甚至还有个 *mgo.Session,这都是可以接受的,在处理时,会自动解开Context,把相应的参数传递到合适的位置,比如回头看看Context接口,Request和Response都能从Context中获取到,不过 *mgo.Session 这又是几个意思?呃,这个其实只要提前通过 Server.ArgBuilder 注册一下如何生成这个参数,就可以获取到了。

把刚才那段代码写完整点:

func get_mongo_session(ctx Context) (*mgo.Session, error) {
    var ret *mgo.Session
    ...
    return ret, nil
}

func dosomething(req wtf.Request, resp wtf.Response, mongo *mgo.Session) {
    ...
}

...

server.ArgBuilder(get_mgo_session)
server.Handle(dosomething, "/dosomething", "GET", "localhost", "POST")
...

如果获取数据有错,则返回的error不为空,此时Server会中止后续处理,当然了,如果需要给客户端返回点啥,比如500之类的,就需要get_mongo_session自己利用一下Context啦。好了,就先说这么些吧。

以下是默认支持的Handle参数类型和简单说明,除了这些参数类型,其他的都需要自己通过ArgBuilder来构造:

  1. wtf.Context : 呃,其实WTF也不是没有Context,也有,只是所有数据都包括在内,使用的时候还得取出来,实在有点不爽
  2. wtf.Request : 封装了 http.Request ,增加了一些辅助的方法
  3. wtf.Response : 封装了 http.ResponseWriter ,增加了一些常用的方法
  4. wtf.Rest : 提供对REST参数的存取
  5. *http.Request : 如果你强烈要求使用最原始的 http.Request 的话
  6. http.ResponseWriter : 如果你强烈要求使用最原始的 http.ResponseWriter 的话

中间件

中间件的作用其实还是很大的,比如所有的请求都要先验证token,而接口一共有那么2、3千个... 估计程序员不用被杀来祭天,自己就挂了。这个时候,只需要写个中间件,挂在所有请求处理之前,咻,世界干净了。

惯例,看例子:

type (
    AuthMid struct {
    }
)

func (am *AuthMid) Priority() int {
    return 0
}
func (am *AuthMid) Proc(ctx wtf.Context) wtf.Context {
    ctx.Response().WriteHeader(http.StatusUnauthorized)
    ctx.Response().WriteString("爷今天不高兴,谁也不让过")
    return nil
}

.
.
.

serv.AddMidware(&AuthMid{})

其中那个Priority方法,是用来做中间件的排序的,数字越小的越靠前,越早被执行。这个优先级的取值是0~100,超出范围的会被截取到这个范围内,即小于0的认为是0,大于100的认为是100。同样优先级的,按照加入的顺序来执行。

Proc方法是需要返回一个Context的,这个Context会用来作为下一个中间件的输入,而如果要终止这个处理链,就像这里的AuthMid一样,只需要返回nil,之后所有的中间件就不会执行了。

接下来讲解CorsMid的实现,更多的例子可以自行参考已经有的几个个实现:GzipMid、StatusCodeMid。需要注意的是,Context中如果有Flush的需求,一定要保证多次调用Flush不会造成危害。

type (
    // 由于返回状态码需要最后处理,这些现场、状态还需要一直保持,因此封装一层writer
	wtf_statuscode_writer struct {
		WriterWrapper
		ctx    Context
		handle map[int]func(Context)
		total  int
	}

	StatusCodeMid struct {
		handle map[int]func(Context)
	}
)

// 将数据写回给客户端
func (sw *wtf_statuscode_writer) Write(in []byte) (int, error) {
	sw.total += len(in)
	return sw.WriterWrapper.Write(in)
}

// Flush 需要保证多次调用无副作用
func (sw *wtf_statuscode_writer) Flush() error {
	info := sw.WriterWrapper.GetWriteInfo()
	if sw.total == 0 && sw.handle != nil {
		if h, exist := sw.handle[info.RespCode()]; exist {
			h(sw.ctx)
		}
	}
	return nil
}

func NewStatusCodeMidware() *StatusCodeMid {
	return &StatusCodeMid{}
}

// Midware可以定一些供外部调用的方法,比如做些配置之类的,此处的Handle就可以用来定义特定返回码的对应处理方法
func (sc *StatusCodeMid) Handle(code int, h func(Context)) *StatusCodeMid {
	if sc.handle == nil {
		sc.handle = make(map[int]func(Context))
	}
	sc.handle[code] = h
	return sc
}

// Priority、Proc是Midware接口中定义的方法,必须要有
func (sc *StatusCodeMid) Priority() int {
	return 1
}

func (sc *StatusCodeMid) Proc(ctx Context) Context {
	writer := &wtf_statuscode_writer{
		WriterWrapper: ctx.HttpResponse(),
		ctx:           ctx,
		handle:        sc.handle,
	}
    // 用封装的Writer新建一个Context,传给下一级Midware
	ret := ctx.Clone(writer)
	return ret
}

先写这么多

累了,如果还有需要补充的,再接着写吧。

Enjoy WTF !!!

Bye

Documentation

Overview

WTF的目标:简洁,组件化。 因此WTF的各部件,都定义为接口,可以随意替换。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllSupportMethods

func AllSupportMethods() []string

func DetectMime

func DetectMime(data []byte, name ...string) string

func MimeIsText

func MimeIsText(m string) bool

func NewFileServer

func NewFileServer(root string) func(Context, Response)

func ValidMethod

func ValidMethod(m string) bool

Types

type Builder

type Builder interface {
	SetWriterBuilder(fn func(Logger, http.ResponseWriter) WriterWrapper) Builder
	SetRequestBuilder(fn func(Logger, *http.Request) Request) Builder
	SetResponseBuilder(fn func(Logger, http.ResponseWriter, Template) Response) Builder
	SetContextBuilder(fn func(Logger, *http.Request, http.ResponseWriter, Template, Builder) Context) Builder
	SetMuxBuilder(fn func() Mux) Builder

	BuildWriter(Logger, http.ResponseWriter) WriterWrapper
	BuildRequest(Logger, *http.Request) Request
	BuildResponse(Logger, http.ResponseWriter, Template) Response
	BuildContext(Logger, *http.Request, http.ResponseWriter, Template, Builder) Context
	BuildMux() Mux
}

func DefaultBuilder

func DefaultBuilder() Builder

type Context

type Context interface {
	// 获取日志对象
	Logger() Logger

	// 获取Builder对象,以创建新的组件
	Builder() Builder

	// 获取客户端发送的原始请求
	HttpRequest() *http.Request

	// Request 获取封装后的客户端请求数据
	Request() Request

	// HttpResponse 获取封装后的http.ResponseWriter
	HttpResponse() WriterWrapper

	// Response 获取封装后的Response
	Response() Response

	// 执行模板,并且返回执行完成后的数据
	Template() Template

	// 设置REST请求的URI参数
	SetRestInfo(Rest)

	// 获取REST请求的URI参数
	RestInfo() Rest

	// Clone 方法根据自身的参数,创建一个新的Context,通常其他参数都不需要改变,只需要改变WriterWrapper,因此Clone的参数只需要提供该变量即可,当然,如果不提供,则返回自身的完全拷贝,但这是无意义的
	Clone(...WriterWrapper) Context
}

Context接口整合了很多处理所需的上下文环境,例如用户的请求Request、输出的接口Response、HTML处理模板Template等

func NewContext

func NewContext(log Logger, req *http.Request, resp http.ResponseWriter, tpl Template, b Builder) Context

type CorsMid

type CorsMid struct {
	// contains filtered or unexported fields
}

func NewCrossOriginMidware

func NewCrossOriginMidware() *CorsMid

func (*CorsMid) AddDomains

func (cm *CorsMid) AddDomains(domain string, others ...string) *CorsMid

func (*CorsMid) AddHeader

func (cm *CorsMid) AddHeader(key, value string) *CorsMid

func (*CorsMid) AllowMethods

func (cm *CorsMid) AllowMethods(m string, ms ...string) *CorsMid

func (*CorsMid) Priority

func (cm *CorsMid) Priority() int

func (*CorsMid) Proc

func (cm *CorsMid) Proc(ctx Context) Context

func (*CorsMid) SetDomains

func (cm *CorsMid) SetDomains(domains []string) *CorsMid

type Error

type Error interface {
	Error() string
	Code() int
	Message() string
}

WTF专有的错误结构,相比标准库里的error,多了Code字段,可以设置自己需要的错误码,同时兼容系统error

func NewError

func NewError(code int, msg string, err ...error) Error

type File

type File interface {
	io.Reader
	io.Writer
	io.Seeker
	io.Closer
	FileInfo() os.FileInfo
	ContentType() string
}

type FileSystem

type FileSystem interface {
	SetFileMapper(m func(Request) []string)
	SetDefaultPages([]string)
	Open(Request, ...int) (File, Error)
	OpenPath(string, ...int) (File, Error)
	Read(Request) ([]byte, Error)
	Write([]byte, Request) Error
	WriteStream(io.Reader, Request) Error
	Append([]byte, Request) Error
	AppendStream(io.Reader, Request) Error
}

func NewFileSystem

func NewFileSystem(base ...string) FileSystem

type Flushable

type Flushable interface {
	// 将缓冲区中的数据写入网络
	Flush() error
}

type GzipMid

type GzipMid struct {
	// contains filtered or unexported fields
}

func NewGzipMidware

func NewGzipMidware(level ...int) *GzipMid

func (*GzipMid) AppendMime

func (gm *GzipMid) AppendMime(ms string, more ...string) *GzipMid

func (*GzipMid) Priority

func (gm *GzipMid) Priority() int

func (*GzipMid) Proc

func (gm *GzipMid) Proc(ctx Context) Context

func (*GzipMid) SetLevel

func (gm *GzipMid) SetLevel(level int) *GzipMid

func (*GzipMid) SetMime

func (gm *GzipMid) SetMime(ms []string) *GzipMid

func (*GzipMid) SetMinSize

func (gm *GzipMid) SetMinSize(size int) *GzipMid

type Logger

type Logger interface {
	Trace(...interface{})
	Tracef(string, ...interface{})
	Debug(...interface{})
	Debugf(string, ...interface{})
	Info(...interface{})
	Infof(string, ...interface{})
	Log(...interface{})
	Logf(string, ...interface{})
	Warn(...interface{})
	Warnf(string, ...interface{})
	Error(...interface{})
	Errorf(string, ...interface{})
	Fatal(...interface{})
	Fatalf(string, ...interface{})
}

WTF所使用的日志接口,如果要替换WTF内置的Logger,只需要实现该接口即可

type Midware

type Midware interface {
	// 插件的优先级,从1-10,数字越低优先级越高,相同优先级的,顺序不保证
	Priority() int

	// 插件的处理函数,并且返回一个Context,作为插件链中下一个插件的输入
	//
	// 如果返回nil,则表示不再继续执行后续的插件了
	Proc(Context) Context
}

type Mux

type Mux interface {
	// 三个参数依次为处理接口、匹配的模式和匹配的HTTP方法
	Handle(func(Context), string, ...string) Error

	// 检查Request是否有匹配的Handler,如果有,则返回Handler,以及对应模式解析后的URI参数
	Match(*http.Request) (func(Context), Rest)
}

Mux接口

func NewWTFMux

func NewWTFMux() Mux

type RESTParam

type RESTParam struct {
	// contains filtered or unexported fields
}

以REST方式的请求,在URI中定义的参数将会被解析成该结构

type RESTParams

type RESTParams []RESTParam

REST方式的请求,URI中定义的参数集合

func (RESTParams) Append

func (p RESTParams) Append(name, value string) RESTParams

增加URI参数

对于重名的问题,不在此处考虑,那是使用者需要考虑的事

func (RESTParams) Get

func (p RESTParams) Get(name string) string

获取命名了的URI参数

例如:/test/:foo,则命名参数为foo

又如:/test/(?P<name>\d+),则命名参数为name

func (RESTParams) GetIndex

func (p RESTParams) GetIndex(i int) string

按索引获取URI参数

例如:/test/:foo/(\d+),第一个参数命名为foo,第二个参数没有命名,只能通过索引取得

type Request

type Request interface {
	// BasicAuth 代理http.Request中的BasicAuth,返回请求头中的验证信息
	BasicAuth() (username, password string, ok bool)

	// Cookie 代理http.Request中的Cookie,返回指定的Cookie
	Cookie(name string) (*http.Cookie, error)

	// Cookkies 代理http.Request中的Cookies,返回所有Cookie
	Cookies() []*http.Cookie

	// MultipartReader 代理http.Request中的MultipartReader,以Reader的形式读取Multipart内容
	MultipartReader() (*multipart.Reader, error)

	// ParseMultipartForm 代理http.Request中的ParseMultipartForm,不过增加可选设置,不设置maxMemory时,默认为16M,并且会自己检测是否需要Parse
	ParseMultipartForm(maxMemory ...int64) error

	// Proto 返回HTTP的版本号
	Proto() (int, int)

	// Referer 返回http.Request.Referer
	Referer() string

	// UserAgent 返回http.Request.UserAgent
	UserAgent() string

	// Method 返回http.Request.Method
	Method() string

	// URL 返回http.Request.URL
	URL() *url.URL

	// GetHeader 返回指定key的Header项,如果key不存在,则返回空字符串
	GetHeader(key string) string

	// ContentLength 返回http.Request.ContentLength,如果为0,表示没有Body,或者不能获取到ContentLength
	ContentLength() int64

	// Host 返回http.Request.Host
	Host() string

	// Forms 返回url请求参数、Post请求参数和Multipart请求参数三个map,并且如果没有解析过,会先解析之后再返回,多次调用不会多次Parse
	Forms() (url.Values, url.Values, *multipart.Form)

	// RemoteAddr 返回http.Request.RemoteAddr
	RemoteAddr() string

	// 获取客户端请求发送来的Body,可以重复获取而不影响已有的数据
	GetBody() (io.Reader, Error)

	// GetBodyData 获取已经传输完成的请求体
	GetBodyData() ([]byte, Error)

	// 将客户端请求发送来的Body解析为Json对象
	GetJsonBody(interface{}) Error

	// GetUploadFile 获取指定key的上传文件,多个上传文件组成数组
	GetUploadFile(key string) ([]UploadFile, Error)
}

Request 封装了http.Request,去掉了http.Request和Client相关的操作函数,增加了一些优化过的方法

func NewRequest

func NewRequest(log Logger, req *http.Request) Request

type Response

type Response interface {
	// Header 函数兼容http.ResponseWriter
	Header() http.Header
	// Write 函数兼容http.ResponseWriter
	Write([]byte) (int, error)
	// WriteHeader 函数兼容http.ResponseWriter
	WriteHeader(int)

	// WriteString 输出字符串到客户端
	WriteString(string) (int, error)

	// 向客户端发送数据流中的所有数据
	WriteStream(io.Reader) (int64, error)

	// 将参数格式化成Json,发送给客户端
	WriteJson(interface{}) (int, error)

	// 将参数格式化成XML,发送给客户端
	WriteXml(interface{}) (int, error)

	// SetHeader 设置Header中的项
	SetHeader(key, value string)

	// 向客户端返回状态码, 如果调用时带了body,则忽略WTF默认的状态码对应的body,而返回此处带的body
	StatusCode(code int, body ...string)

	// Execute 解析并执行指定的模板,直接将输出写入Response,如果发生错误,返回Error,同时不写任何数据到Response,可以有修改StatusCode的机会
	Execute(name string, obj interface{}) Error

	// 返回状态码404,如果调用时带了body,则忽略WTF默认的body,而返回此处带的body
	NotFound(body ...string)

	// 向客户端发送重定向状态码
	Redirect(url string)

	// 通知客户端,继续请求指定的url,如果有body,可以在调用时指定
	Follow(url string, body ...string)

	// 允许跨域请求,如果还允许客户端发送cookie,可以由第二个参数指定,默认为false
	CrossOrigin(Request, ...string)
}

WTF专用的输出结构接口,注意,区别于http.Response,其中定义了一些常用的便利接口。

func NewResponse

func NewResponse(log Logger, resp http.ResponseWriter, tpl Template) Response

type ResponseInfo

type ResponseInfo interface {
	RespCode() int
	WriteBytes() int64
}

定义了Response之后的一些处理数据,在处理完成后,输出日志时会从该结构中获取所需的数据

type Rest

type Rest interface {
	// 增加URI参数
	//
	// 对于重名的问题,不在此处考虑,那是使用者需要保证的事
	Append(name, value string) RESTParams

	// 获取命名了的URI参数,没有获取到则返回空字符串
	//
	// 例如:/test/:foo,则命名参数为foo
	//
	// 又如:/test/(?P<name>\d+),则命名参数为name
	Get(name string) string

	// 按索引获取URI参数,没有获取到则返回空字符串
	//
	// 例如:/test/:foo/(\d+),第一个参数命名为foo,第二个参数没有命名,只能通过索引取得
	GetIndex(i int) string
}

Rest 定义了REST参数相关的操作

type Server

type Server interface {
	http.Handler

	// SetBuilder 设置各个组件的Builder方法
	SetBuilder(Builder)

	// GetBuilder 获取Server中当前Builder,可以在获取之后,修改自定义的Builder,再设置回去
	GetBuilder() Builder

	// 设置Server所使用的Logger
	SetLogger(Logger)

	// 设置Server所使用的模板
	SetTemplate(Template)

	// 绑定Handler函数里自定义参数的构造方法,必须是 func(Context) ??? 类型的函数,会自动根据返回值映射到对应的类型上
	//
	// 注意限制:fn必须为函数类型,只能有一个入参,入参类型Context,只能有两个出参,第一个类型不限,第二个必须为error,返回error会导致中止后续处理,打印错误日志,如果有需要给客户端输入,需要自己通过Context处理
	ArgBuilder(fn interface{}) error

	// 获取该Server正在使用的模板
	Template() Template

	// 直接设置一个完成状态的Mux
	SetMux(Mux, ...string)

	// 向链条中插入一个Midware
	AddMidware(Midware)

	// 定义一种更灵活的Handle方法,可以根据handler的参数内容调整输入参数,取消Handler结构
	Handle(interface{}, string, ...string) Error
}

服务的主体类,是所有功能的入口

func NewServer

func NewServer(logger ...Logger) Server

用默认的组件们创建Server,默认组件是指Logger使用了github.com/i11cn/go_logger, 支持vhost,Mux使用了WTF自己实现的Mux,Context使用了WTF自己实现的Context, Template也是WTF实现的。

type StatusCodeMid

type StatusCodeMid struct {
	// contains filtered or unexported fields
}

func NewStatusCodeMidware

func NewStatusCodeMidware() *StatusCodeMid

func (*StatusCodeMid) Handle

func (sc *StatusCodeMid) Handle(code int, h func(Context)) *StatusCodeMid

func (*StatusCodeMid) Priority

func (sc *StatusCodeMid) Priority() int

func (*StatusCodeMid) Proc

func (sc *StatusCodeMid) Proc(ctx Context) Context

type Template

type Template interface {
	// 绑定管道函数
	BindPipe(key string, fn interface{}) Template

	// 加载字符串作为模板
	LoadText(string) Template

	// 加载文件作为模板,可以同时加载多个文件
	LoadFiles(files ...string) Template

	// 执行模板,注意模板名称和加载的文件名相同(不包括路径)
	Execute(key string, data interface{}) ([]byte, Error)
}

HTML的模板处理接口

func NewTemplate

func NewTemplate() Template

type UploadFile

type UploadFile interface {
	io.Reader
	io.ReaderAt
	io.Seeker
	io.Closer

	Filename() string
	Size() int64
	ContentType() string
	Header() textproto.MIMEHeader
}

type WriteInfo

type WriteInfo interface {
	RespCode() int
	WriteBytes() int64
}

定义了Write之后的的一些处理数据,在处理完成后,输出日志时会从该结构中获取所需的数据

type WriterWrapper

type WriterWrapper interface {
	Flushable

	// Header 函数兼容http.ResponseWriter
	Header() http.Header
	// Write 函数兼容http.ResponseWriter
	Write([]byte) (int, error)
	// WriteHeader 函数兼容http.ResponseWriter
	WriteHeader(int)

	// GetWriteInfo 获取输出的一些信息
	GetWriteInfo() WriteInfo
}

WriterWrapper 封装了http.ResponseWriter,并且增加了缓存,增加了计数统计

func NewWriterWrapper

func NewWriterWrapper(log Logger, resp http.ResponseWriter) WriterWrapper

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL