Skip to main content

Handler

· 6 min read

用于处理HTTP请求并写入响应

对应函数:

普通路由注册

*Server.AddHttpHandler(path, HttpMethod string, handler RouteDisPatch.HttpHandle)

参数路由注册(参数默认位置在请求体/请求头)

也有更方便的方式,请查看下文的feature

*Server.AddBodyParamHandler(path, HttpMethod string, param interface{}, handler RouteDisPatch.HttpHandle)

*Server.AddHeaderParamHandler(path, HttpMethod string, param interface{}, handler RouteDisPatch.HttpHandle)

参数说明:

path

绑定的http请求路径 请求值可以为:

  1. 正常字符串:

/helloWorld,匹配的就是访问https://{basURL}/helloWorld的请求

  1. 通配符*或**

*匹配当前一级的所有目录

**匹配当前目录下的所有请求

/user/role/*/userData匹配的就是访问如:

https://{basURL}/user/role/1/userData

https://{basURL}/user/role/2/userData

的所有请求

/user/role/**匹配的就是访问如:

https://{basURL}/user/role/abc

https://{basURL}/user/role/dc/userData

的所有请求

  1. 规则请求

类似于:{name(string):step(uint)} 例子:

/user/{userName:1}

/userName/{fullName:2}

对应匹配的请求路径:

/user/ben

/userName/Alice/Center

注意: 推荐和param,参数路由注册一起使用

HttpMethod

Http请求方法,和http规范中的请求方法同步,推荐直接使用

http.Methodxxx

进行声明

param

参数路由必填参数,必须是结构体指针(如欲使用自动注入请求参数的话)

对应函数

默认参数在请求体中

*Server.AddBodyParamHandler(path, HttpMethod string, param interface{}, handler RouteDisPatch.HttpHandle)

参数默认在请求头中

*Server.AddHeaderParamHandler(path, HttpMethod string, param interface{}, handler RouteDisPatch.HttpHandle)

设计初衷:

在开发中经常会有一个接口参数会来自如下地方:

  1. 请求头拿到token/其他权限相关数据
  2. 请求体中拿到实际请求的数据
  3. 请求path中拿到id等相关的路径信息(结合path中的规则请求使用)

导致可能一个很简单的接口,需要从三个不同的地方分别解析得到数据,所以,本框架将这三个地方的数据都进行一个处理,只需开发者注册路由时调用一个不同的注册函数即可在HttpHandle主体处理函数拿到对应的数据

对于param结构体没有太多的要求,如果是调用AddBodyParamHandler进行注册的话,则请求会从请求的Form表单获取数据,如果是AddHeaderParamHandler的话,请求会从请求头中拿取数据

但请注意,如果是需要从请求头/Form表单拿取数据的话,那么结构体中不能再嵌套结构体,并且类型只能是golang的基础数据类型,不然会注入失败(json数据不受单层结构体的限制,AddBodyParamHandler和AddHeaderParamHandler均可注入成功)

额外说明

如果是既有formData/headerData的情况,可以使用结构体注释来标注,目前的注释结构如下:

const (
locationTag = "quickLoc" //参数位置在哪
defaultValue = "quickDefault" //参数默认值
param = "quickParam" //参数对应的param名字,类似于 `json:"name"`
)

const (
header = "header" // http请求头传参
body = "body" //Body传参(目前暂时未做对应操作)
reqParam = "param" //param传参,类似于www.baidu.com?name=Baidu
)

举个例子:

package main
import(
"fmt"
"github.com/wangshiben/QuicFrameWork/server"
"github.com/wangshiben/QuicFrameWork/server/RouteDisPatch"
"github.com/wangshiben/QuicFrameWork/server/RouteHand"
"net/http"
)
type TestStruct struct {
Name string
RequestParam string `quickLoc:"param"`
Header string `quickLoc:"header"`
Age int `quickLoc:"param"`
}
func main() {
//可信的证书
newServer := server.NewServer("cert.pem", "cert.key", ":4445")
newServer.AddBodyParamHandler("/temp/**", http.MethodPost, &TestStruct{}, func(w http.ResponseWriter, r *RouteDisPatch.Request) {
testStruct := r.Param.(*TestStruct)
fmt.Println(*testStruct)
})
}

HttpHandle

处理函数,对于经过Filter过滤的请求进行实际处理

函数具体格式如下:

 func(w http.ResponseWriter, r *RouteDisPatch.Request) {

}

  1. http.ResponseWriter:

就是net/http包中的ResponseWriter,可直接使用其相应参数

  1. RouteDisPatch.Request:

内封装了两个参数:http.Request和Param interface{}

http.Request就是net/http包中原生的http.Request,Param interface{}就是在调用AddBodyParamHandler或AddHeaderParamHandler中的Param使用时,需要对其强制转换一下,如果不想手写强制转换,推荐使用下面feature的功能

feature(还未严格测试,如有bug请及时反馈)

主要是简化自动注入流程,不需要开发人员手动强制转换类型

可以移步至源码查看,主要是调用之前新增了一次强制转换: https://github.com/wangshiben/QuicFrameWork/blob/master/server/RouteHand/routAdd.go

没有文档是因为可能随时都在变

调用示例:

package main
import(
"fmt"
"github.com/wangshiben/QuicFrameWork/server"
"github.com/wangshiben/QuicFrameWork/server/RouteDisPatch"
"github.com/wangshiben/QuicFrameWork/server/RouteHand"
"net/http"
)
type TestStruct struct {
Name string
RequestParam string `quickLoc:"param"`
Header string `quickLoc:"header"`
Age int `quickLoc:"param"`
}
func main() {
//可信的证书
newServer := server.NewServer("cert.pem", "cert.key", ":4445")
RouteHand.PostAutowired(newServer, "/mmm/bck/**", func(q *RouteHand.QuickFrameWork[TestStruct]) {
param := q.Param
fmt.Println(param)
})
}

HttpFilter

· 4 min read

其实对于Filter也好,Middleware也罢,他们的基本流程的都是一样的,都是在Handler处理HTTP请求之前对Http请求进行一个预操作,但两者的区别主要还是在使用面向的对象上

Filter注重于在某个http请求的Path之前进行调用,换句话说,它专注在http的Path进行匹配和处理

Middleware注重于在执行代码/函数之前进行调用,可复用程度广,但容易造成一些可读性的问题

所以本框架为了保证开发人员的轻量化开发,采用的是Filter式的请求拦截策略

涉及函数:

*Server.AddFilter(path string, filter RouteDisPatch.HttpFilter)

参数说明

path

绑定的http拦截器的路径 请求值可以为:

  1. 正常字符串:

/helloWorld,匹配的就是访问https://{basURL}/helloWorld的请求

  1. 通配符*或**

*拦截当前一级的所有目录

**拦截当前目录下的所有请求

/user/role/*/userData拦截的就是访问如:

https://{basURL}/user/role/1/userData

https://{basURL}/user/role/2/userData

的所有请求

/user/role/**拦截的就是访问如:

https://{basURL}/user/role/abc

https://{basURL}/user/role/dc/userData

的所有请求

HttpFilter

拦截函数,对于每个http请求进行链式调用和处理

函数具体格式如下:

 func(w http.ResponseWriter, r *RouteDisPatch.Request, next RouteDisPatch.Next) {

}

其中http.ResponseWriter是golang原生net/http``包中的ResponseWriter

RouteDisPatch.Request是对golang原生net/http包进行了一层封装,具体的可查看Handler中的定义

RouteDisPatch.Next是拦截器的链式调用:

在一个具体路径上,如/name/age/id的实际请求上,可能会有如下path的拦截器: /name/**,/name/age/**,/name/age/id,那么,这一系列的拦截器加Handler函数就构成了一套完整的请求链,排列方式是:父级路径的拦截器在前,子级拦截器的路径在后,最后才是对应路径的Handler函数

拦截器执行下一步是调用next函数,将http.ResponseWriter, RouteDisPatch.Request传递下去即可,框架在执行到末端时会自动调用Handler

示例:

package main
import(
"fmt"
"github.com/wangshiben/QuicFrameWork/server"
"github.com/wangshiben/QuicFrameWork/server/RouteDisPatch"
"github.com/wangshiben/QuicFrameWork/server/RouteHand"
"net/http"
)
func main() {
//可信的证书
newServer := server.NewServer("cert.pem", "cert.key", ":4445")
newServer.AddFilter("/test/**", func(w http.ResponseWriter, r *RouteDisPatch.Request, next RouteDisPatch.Next) {
fmt.Println("拦截到了请求")
next.Next(w, r)
fmt.Println("拦截请求结束")
})
}

CROS(跨域配置)

这部分感谢@tiansuo114进行开发测试

主要函数:

type CORSConfig struct {
//均为http协议中Access-Control-xxx的响应头
AllowOrigins []string//允许的源
AllowMethods []string//允许的请求方法
AllowHeaders []string//允许的请求头
AllowCredentials bool //允许凭证
ExposeHeaders []string//允许前端JS访问的响应头
MaxAge int//最大存活时间
}

*Server.CROS(path string, cconf ...cors.CORSConfig) {

}

参数说明:

path

同上述的HttpFilter

CORSConfig

跨域配置信息,可查看上述注释

用法:

若没有特殊要求,则推荐直接使用如下方式进行跨域配置:

package main
import(
"fmt"
"github.com/wangshiben/QuicFrameWork/server"
"github.com/wangshiben/QuicFrameWork/server/RouteDisPatch"
"github.com/wangshiben/QuicFrameWork/server/RouteHand"
"net/http"
)
func main() {
//可信的证书
newServer := server.NewServer("cert.pem", "cert.key", ":4445")
newServer.CROS("/**")
}

当时设计此函数时,因为golang没有多态这个概念,所以使用了参数切片来进行伪多态,如果有特殊需求的话,只需要传递一个CROSConfig即可,传多个Config默认启用第一个

API文档

· One min read

更快的传输,更轻量化开发

整个框架对外提供函数只有如下部分:

  1. 处理器(Handler)

用于处理http请求

  1. 拦截器/中间件(Filter)

用于在http请求之前对请求进行拦截处理

Server

· 2 min read

Server包作为整个服务的提供者和启动入口,这里的Server指的是程序启动和初始化相关的函数API

目前Server提供了两个启动方式:

  1. 基于TLS证书启动,https访问
  2. Http启动(还在测试中,属于feature功能)

TLS启动:

相关函数:

初始化Server:server.NewServer(TLSPem, TLSKey, port string)

启动Server:*Server.StartServer()

参数说明:

TSLPem和TLSKey

TSL证书的pem和key文件路径,可以是相对路径也可以是绝对路径,如果没有值则传""即可(空值为默认自动生成证书,生成自签名证书)

注意 TSLPem和TLSKey必须同时传,不能只传一个,否则会启动失败

port

监听的端口号,格式为: :number,会占用目标端口的TCP和UDP端口,请提前开启目标端口的防火墙,以免接收不到包

Http启动

初始化Server:server.NewHttpServer(port string)

启动HttpServer:*Server.StartHttpSerer()

参数说明:

port

监听的端口号,格式为: :number,会占用目标端口的TCP端口,请提前开启目标端口的防火墙,以免接收不到包