mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
完善并改进gbinary,gconv包类型转换功能,改进ghttp.Response对象操作
This commit is contained in:
8
TODO
8
TODO
@ -1,5 +1,3 @@
|
||||
1. gconv完善针对不同类型的判断,例如:尽量减少sprintf("%v", xxx)来执行string类型的转换;
|
||||
2. gdb Where方法参数的改进,研究是否可以将string参数类型修改为interfaceP{;
|
||||
3. 增加对于数据表Model的封装;
|
||||
4. ghttp.Server请求执行中增加服务退出的方法,不再执行后续操作;
|
||||
5. ghttp.Response对象完善并改进数据返回方法(Write/WriteString);
|
||||
1. gdb Where方法参数的改进,研究是否可以将string参数类型修改为interfaceP{;
|
||||
2. 增加对于数据表Model的封装;
|
||||
3. ghttp.Server请求执行中增加服务退出的方法,不再执行后续操作;
|
||||
@ -8,33 +8,43 @@
|
||||
package gbinary
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"math"
|
||||
)
|
||||
|
||||
// 二进制位(0|1)
|
||||
type Bit int8
|
||||
|
||||
// 针对基本类型进行二进制打包,支持的基本数据类型包括:int/8/16/32/64、uint/8/16/32/64、float32/64、bool、string、[]byte
|
||||
func Encode(vs ...interface{}) ([]byte, error) {
|
||||
// 其他未知类型使用 fmt.Sprintf("%v", value) 转换为字符串之后处理
|
||||
func Encode(vs ...interface{}) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
for i := 0; i < len(vs); i++ {
|
||||
var err error = nil
|
||||
switch vs[i].(type) {
|
||||
case int: buf.Write(EncodeInt(vs[i].(int)))
|
||||
case uint: buf.Write(EncodeUint(vs[i].(uint)))
|
||||
case bool: buf.Write(EncodeBool(vs[i].(bool)))
|
||||
case string: buf.Write(EncodeString(vs[i].(string)))
|
||||
case []byte: buf.Write(vs[i].([]byte))
|
||||
switch value := vs[i].(type) {
|
||||
case int: buf.Write(EncodeInt(value))
|
||||
case int8: buf.Write(EncodeInt8(value))
|
||||
case int16: buf.Write(EncodeInt16(value))
|
||||
case int32: buf.Write(EncodeInt32(value))
|
||||
case int64: buf.Write(EncodeInt64(value))
|
||||
case uint: buf.Write(EncodeUint(value))
|
||||
case uint8: buf.Write(EncodeUint8(value))
|
||||
case uint16: buf.Write(EncodeUint16(value))
|
||||
case uint32: buf.Write(EncodeUint32(value))
|
||||
case uint64: buf.Write(EncodeUint64(value))
|
||||
case bool: buf.Write(EncodeBool(value))
|
||||
case string: buf.Write(EncodeString(value))
|
||||
case []byte: buf.Write(value)
|
||||
case float32: buf.Write(EncodeFloat32(value))
|
||||
case float64: buf.Write(EncodeFloat64(value))
|
||||
default:
|
||||
err = binary.Write(buf, binary.LittleEndian, vs[i])
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err := binary.Write(buf, binary.LittleEndian, value); err != nil {
|
||||
buf.Write(EncodeString(fmt.Sprintf("%v", value)))
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// 整形二进制解包,注意第二个及其后参数为字长确定的整形变量的指针地址,以便确定解析的[]byte长度,
|
||||
|
||||
@ -29,7 +29,7 @@ type Request struct {
|
||||
|
||||
// 创建一个Request对象
|
||||
func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request {
|
||||
return &Request{
|
||||
request := &Request{
|
||||
parsedGet : gtype.NewBool(),
|
||||
parsedPost : gtype.NewBool(),
|
||||
values : make(map[string][]string),
|
||||
@ -40,6 +40,10 @@ func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request {
|
||||
ResponseWriter : w,
|
||||
},
|
||||
}
|
||||
// 会话处理
|
||||
request.Cookie = GetCookie(request)
|
||||
request.Session = GetSession(request)
|
||||
return request
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -10,6 +10,8 @@ package ghttp
|
||||
import (
|
||||
"sync"
|
||||
"net/http"
|
||||
"gitee.com/johng/gf/g/util/gconv"
|
||||
"gitee.com/johng/gf/g/encoding/gparser"
|
||||
)
|
||||
|
||||
// 服务端请求返回对象
|
||||
@ -19,39 +21,52 @@ type Response struct {
|
||||
buffer []byte // 每个请求的返回数据缓冲区
|
||||
}
|
||||
|
||||
// 返回的固定JSON数据结构
|
||||
//type ResponseJson struct {
|
||||
// Result int `json:"result"` // 标识消息状态
|
||||
// Message string `json:"message"` // 消息使用string存储
|
||||
// Data []byte `json:"data"` // 二进制数据(不管什么数据结构)
|
||||
//}
|
||||
|
||||
// 返回信息(byte)
|
||||
func (r *Response) Write(content []byte) {
|
||||
// 返回信息,任何变量自动转换为bytes
|
||||
func (r *Response) Write(content interface{}) {
|
||||
r.bufmu.Lock()
|
||||
defer r.bufmu.Unlock()
|
||||
r.buffer = append(r.buffer, content...)
|
||||
r.buffer = append(r.buffer, gconv.Bytes(content)...)
|
||||
r.bufmu.Unlock()
|
||||
}
|
||||
|
||||
// 返回信息(string)
|
||||
func (r *Response) WriteString(content string) {
|
||||
r.bufmu.Lock()
|
||||
defer r.bufmu.Unlock()
|
||||
r.buffer = append(r.buffer, content...)
|
||||
// 返回JSON
|
||||
func (r *Response) WriteJson(content interface{}) error {
|
||||
if b, err := gparser.VarToJson(content); err != nil {
|
||||
return err
|
||||
} else {
|
||||
r.Header().Set("Content-Type", "application/json")
|
||||
r.Write(b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 返回固定格式的json
|
||||
//func (r *Response) WriteJson(result int, message string, data []byte) error {
|
||||
// r.Header().Set("Content-Type", "application/json")
|
||||
// r.bufmu.Lock()
|
||||
// defer r.bufmu.Unlock()
|
||||
// if jsonstr, err := gjson.Encode(ResponseJson{ result, message, data }); err != nil {
|
||||
// return err
|
||||
// } else {
|
||||
// r.buffer = append(r.buffer, jsonstr...)
|
||||
// }
|
||||
// return nil
|
||||
//}
|
||||
// 返回XML
|
||||
func (r *Response) WriteXml(content interface{}, rootTag...string) error {
|
||||
if b, err := gparser.VarToXml(content, rootTag...); err != nil {
|
||||
return err
|
||||
} else {
|
||||
r.Header().Set("Content-Type", "application/xml")
|
||||
r.Write(b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 返回HTTP Code状态码
|
||||
func (r *Response) WriteStatus(code int, content...string) {
|
||||
r.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
r.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
if len(content) > 0 {
|
||||
r.Write(content[0])
|
||||
} else {
|
||||
r.Write(http.StatusText(code))
|
||||
}
|
||||
r.WriteHeader(code)
|
||||
}
|
||||
|
||||
// 返回location标识,引导客户端跳转
|
||||
func (r *Response) RedirectTo(location string) {
|
||||
r.Header().Set("Location", location)
|
||||
r.WriteHeader(http.StatusFound)
|
||||
}
|
||||
|
||||
// 获取当前缓冲区中的数据
|
||||
func (r *Response) Buffer() []byte {
|
||||
@ -60,19 +75,26 @@ func (r *Response) Buffer() []byte {
|
||||
return r.buffer
|
||||
}
|
||||
|
||||
// 手动设置缓冲区内容
|
||||
func (r *Response) SetBuffer(buffer []byte) {
|
||||
r.bufmu.Lock()
|
||||
r.buffer = buffer
|
||||
r.bufmu.Unlock()
|
||||
}
|
||||
|
||||
// 清空缓冲区内容
|
||||
func (r *Response) ClearBuffer() {
|
||||
r.bufmu.Lock()
|
||||
defer r.bufmu.Unlock()
|
||||
r.buffer = make([]byte, 0)
|
||||
r.bufmu.Unlock()
|
||||
}
|
||||
|
||||
// 输出缓冲区数据到客户端
|
||||
func (r *Response) OutputBuffer() {
|
||||
r.bufmu.Lock()
|
||||
defer r.bufmu.Unlock()
|
||||
if len(r.buffer) > 0 {
|
||||
r.ResponseWriter.Write(r.buffer)
|
||||
r.buffer = make([]byte, 0)
|
||||
}
|
||||
r.bufmu.Unlock()
|
||||
}
|
||||
|
||||
@ -30,22 +30,33 @@ func (s *Server)defaultHttpHandle(w http.ResponseWriter, r *http.Request) {
|
||||
// 其次,如果没有对应的自定义处理接口配置,那么走默认的域名处理接口配置;
|
||||
// 最后,如果以上都没有找到处理接口,那么进行文件处理;
|
||||
func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
// 创建请求处理对象
|
||||
request := newRequest(s, r, w)
|
||||
// 事件 - BeforeServe
|
||||
s.callHookHandler(request, "BeforeServe")
|
||||
if h := s.getHandler(request); h != nil {
|
||||
s.callHandler(h, request)
|
||||
} else {
|
||||
s.serveFile(w, r)
|
||||
s.serveFile(request)
|
||||
}
|
||||
// 事件 - AfterServe
|
||||
s.callHookHandler(request, "AfterServe")
|
||||
// 事件 - BeforeOutput
|
||||
s.callHookHandler(request, "BeforeOutput")
|
||||
// 输出Cookie
|
||||
request.Cookie.Output()
|
||||
// 输出缓冲区
|
||||
request.Response.OutputBuffer()
|
||||
// 事件 - AfterOutput
|
||||
s.callHookHandler(request, "AfterOutput")
|
||||
// 将Request对象指针丢到队列中异步处理
|
||||
s.closeQueue.PushBack(request)
|
||||
}
|
||||
|
||||
// 初始化控制器
|
||||
func (s *Server)callHandler(h *HandlerItem, r *Request) {
|
||||
// 会话处理
|
||||
r.Cookie = GetCookie(r)
|
||||
r.Session = GetSession(r)
|
||||
|
||||
// 请求处理
|
||||
s.callHookHandler(r, "BeforeServe")
|
||||
|
||||
if h.faddr == nil {
|
||||
// 新建一个控制器对象处理请求
|
||||
c := reflect.New(h.ctype)
|
||||
@ -55,23 +66,11 @@ func (s *Server)callHandler(h *HandlerItem, r *Request) {
|
||||
} else {
|
||||
h.faddr(r)
|
||||
}
|
||||
s.callHookHandler(r, "AfterServe")
|
||||
|
||||
s.callHookHandler(r, "BeforeOutput")
|
||||
|
||||
// 输出Cookie
|
||||
r.Cookie.Output()
|
||||
// 输出缓冲区
|
||||
r.Response.OutputBuffer()
|
||||
|
||||
s.callHookHandler(r, "AfterOutput")
|
||||
|
||||
// 将Request对象指针丢到队列中异步处理
|
||||
s.closeQueue.PushBack(r)
|
||||
}
|
||||
|
||||
// 处理静态文件请求
|
||||
func (s *Server)serveFile(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server)serveFile(r *Request) {
|
||||
uri := r.URL.String()
|
||||
if s.config.ServerRoot != "" {
|
||||
// 获取文件的绝对路径
|
||||
@ -79,17 +78,17 @@ func (s *Server)serveFile(w http.ResponseWriter, r *http.Request) {
|
||||
path = path + uri
|
||||
path = gfile.RealPath(path)
|
||||
if path != "" {
|
||||
s.doServeFile(w, r, path)
|
||||
s.doServeFile(r, path)
|
||||
} else {
|
||||
s.NotFound(w, r)
|
||||
r.Response.WriteStatus(http.StatusNotFound)
|
||||
}
|
||||
} else {
|
||||
s.NotFound(w, r)
|
||||
r.Response.WriteStatus(http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
// http server静态文件处理
|
||||
func (s *Server)doServeFile(w http.ResponseWriter, r *http.Request, path string) {
|
||||
func (s *Server)doServeFile(r *Request, path string) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return
|
||||
@ -101,53 +100,41 @@ func (s *Server)doServeFile(w http.ResponseWriter, r *http.Request, path string)
|
||||
fpath := path + "/" + file
|
||||
if gfile.Exists(fpath) {
|
||||
f.Close()
|
||||
s.doServeFile(w, r, fpath)
|
||||
s.doServeFile(r, fpath)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if s.config.IndexFolder {
|
||||
s.listDir(w, f)
|
||||
s.listDir(r, f)
|
||||
} else {
|
||||
s.ResponseStatus(w, http.StatusForbidden)
|
||||
r.Response.WriteStatus(http.StatusForbidden)
|
||||
}
|
||||
} else {
|
||||
http.ServeContent(w, r, info.Name(), info.ModTime(), f)
|
||||
// 读取文件内容返回
|
||||
http.ServeContent(r.Response.ResponseWriter, &r.Request, info.Name(), info.ModTime(), f)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
// 目录列表
|
||||
func (s *Server)listDir(w http.ResponseWriter, f http.File) {
|
||||
func (s *Server)listDir(r *Request, f http.File) {
|
||||
dirs, err := f.Readdir(-1)
|
||||
if err != nil {
|
||||
http.Error(w, "Error reading directory", http.StatusInternalServerError)
|
||||
r.Response.WriteStatus(http.StatusInternalServerError, "Error reading directory")
|
||||
return
|
||||
}
|
||||
sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() })
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
fmt.Fprintf(w, "<pre>\n")
|
||||
r.Response.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
r.Response.Write("<pre>\n")
|
||||
for _, d := range dirs {
|
||||
name := d.Name()
|
||||
if d.IsDir() {
|
||||
name += "/"
|
||||
}
|
||||
u := url.URL{Path: name}
|
||||
fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", u.String(), ghtml.SpecialChars(name))
|
||||
r.Response.Write(fmt.Sprintf("<a href=\"%s\">%s</a>\n", u.String(), ghtml.SpecialChars(name)))
|
||||
}
|
||||
fmt.Fprintf(w, "</pre>\n")
|
||||
r.Response.Write("</pre>\n")
|
||||
}
|
||||
|
||||
// 返回http状态码,并使用默认配置的字符串返回信息
|
||||
func (s *Server)ResponseStatus(w http.ResponseWriter, code int) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(code)
|
||||
w.Write([]byte(http.StatusText(code)))
|
||||
}
|
||||
|
||||
// 404
|
||||
func (s *Server)NotFound(w http.ResponseWriter, r *http.Request) {
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
@ -5,13 +5,12 @@
|
||||
// You can obtain one at https://gitee.com/johng/gf.
|
||||
|
||||
// 类型转换.
|
||||
// 如果给定的interface{}参数不是指定转换的输出类型,那么会进行强制转换,效率会比较低,
|
||||
// 建议已知类型的转换自行调用相关方法来单独处理。
|
||||
// 内部使用了bytes作为底层转换类型,效率很高。
|
||||
package gconv
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"gitee.com/johng/gf/g/encoding/gbinary"
|
||||
)
|
||||
|
||||
func Bytes(i interface{}) []byte {
|
||||
@ -21,10 +20,11 @@ func Bytes(i interface{}) []byte {
|
||||
if r, ok := i.([]byte); ok {
|
||||
return r
|
||||
} else {
|
||||
return []byte(String(i))
|
||||
return gbinary.Encode(i)
|
||||
}
|
||||
}
|
||||
|
||||
// 基础的字符串类型转换
|
||||
func String(i interface{}) string {
|
||||
if i == nil {
|
||||
return ""
|
||||
@ -32,7 +32,7 @@ func String(i interface{}) string {
|
||||
if r, ok := i.(string); ok {
|
||||
return r
|
||||
} else {
|
||||
return fmt.Sprintf("%v", i)
|
||||
return string(Bytes(i))
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,19 +73,97 @@ func Int(i interface{}) int {
|
||||
if v, ok := i.(int); ok {
|
||||
return v
|
||||
}
|
||||
v, _ := strconv.Atoi(String(i))
|
||||
return v
|
||||
return gbinary.DecodeToInt(Bytes(i))
|
||||
}
|
||||
|
||||
func Uint (i interface{}) uint {
|
||||
func Int8(i interface{}) int8 {
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
if v, ok := i.(int8); ok {
|
||||
return v
|
||||
}
|
||||
return gbinary.DecodeToInt8(Bytes(i))
|
||||
}
|
||||
|
||||
func Int16(i interface{}) int16 {
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
if v, ok := i.(int16); ok {
|
||||
return v
|
||||
}
|
||||
return gbinary.DecodeToInt16(Bytes(i))
|
||||
}
|
||||
|
||||
func Int32(i interface{}) int32 {
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
if v, ok := i.(int32); ok {
|
||||
return v
|
||||
}
|
||||
return gbinary.DecodeToInt32(Bytes(i))
|
||||
}
|
||||
|
||||
func Int64(i interface{}) int64 {
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
if v, ok := i.(int64); ok {
|
||||
return v
|
||||
}
|
||||
return gbinary.DecodeToInt64(Bytes(i))
|
||||
}
|
||||
|
||||
func Uint(i interface{}) uint {
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
if v, ok := i.(uint); ok {
|
||||
return v
|
||||
}
|
||||
v, _ := strconv.ParseUint(String(i), 10, 8)
|
||||
return uint(v)
|
||||
return gbinary.DecodeToUint(Bytes(i))
|
||||
}
|
||||
|
||||
func Uint8(i interface{}) uint8 {
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
if v, ok := i.(uint8); ok {
|
||||
return v
|
||||
}
|
||||
return gbinary.DecodeToUint8(Bytes(i))
|
||||
}
|
||||
|
||||
func Uint16(i interface{}) uint16 {
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
if v, ok := i.(uint16); ok {
|
||||
return v
|
||||
}
|
||||
return gbinary.DecodeToUint16(Bytes(i))
|
||||
}
|
||||
|
||||
func Uint32(i interface{}) uint32 {
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
if v, ok := i.(uint32); ok {
|
||||
return v
|
||||
}
|
||||
return gbinary.DecodeToUint32(Bytes(i))
|
||||
}
|
||||
|
||||
func Uint64(i interface{}) uint64 {
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
if v, ok := i.(uint64); ok {
|
||||
return v
|
||||
}
|
||||
return gbinary.DecodeToUint64(Bytes(i))
|
||||
}
|
||||
|
||||
func Float32 (i interface{}) float32 {
|
||||
@ -95,8 +173,7 @@ func Float32 (i interface{}) float32 {
|
||||
if v, ok := i.(float32); ok {
|
||||
return v
|
||||
}
|
||||
v, _ := strconv.ParseFloat(String(i), 8)
|
||||
return float32(v)
|
||||
return gbinary.DecodeToFloat32(Bytes(i))
|
||||
}
|
||||
|
||||
func Float64 (i interface{}) float64 {
|
||||
@ -106,6 +183,5 @@ func Float64 (i interface{}) float64 {
|
||||
if v, ok := i.(float64); ok {
|
||||
return v
|
||||
}
|
||||
v, _ := strconv.ParseFloat(String(i), 8)
|
||||
return v
|
||||
return gbinary.DecodeToFloat64(Bytes(i))
|
||||
}
|
||||
|
||||
@ -1,24 +1,28 @@
|
||||
package main
|
||||
|
||||
import "gitee.com/johng/gf/g/net/ghttp"
|
||||
import (
|
||||
"gitee.com/johng/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ghttp.GetServer().BindHandler("get:/h", func(r *ghttp.Request) {
|
||||
r.Response.WriteString("hello world")
|
||||
//r.Response.RedirectTo("http://www.baidu.com/")
|
||||
r.Response.Write("hello world")
|
||||
//r.Response.WriteStatus(302)
|
||||
})
|
||||
|
||||
ghttp.GetServer().BindHandler("/:name/*any", func(r *ghttp.Request) {
|
||||
r.Response.WriteString("any")
|
||||
r.Response.WriteString(r.GetQueryString("name"))
|
||||
r.Response.WriteString(r.GetQueryString("any"))
|
||||
r.Response.Write("any")
|
||||
r.Response.Write(r.GetQueryString("name"))
|
||||
r.Response.Write(r.GetQueryString("any"))
|
||||
})
|
||||
//ghttp.GetServer().BindHandler("/:name/action", func(r *ghttp.Request) {
|
||||
// r.Response.WriteString(r.GetQueryString("name"))
|
||||
//})
|
||||
ghttp.GetServer().BindHandler("/:name/:action/:aaa", func(r *ghttp.Request) {
|
||||
r.Response.WriteString("name")
|
||||
r.Response.WriteString(r.GetQueryString("name"))
|
||||
r.Response.WriteString(r.GetQueryString("action"))
|
||||
r.Response.Write("name")
|
||||
r.Response.Write(r.GetQueryString("name"))
|
||||
r.Response.Write(r.GetQueryString("action"))
|
||||
})
|
||||
ghttp.GetServer().SetPort(10000)
|
||||
ghttp.GetServer().Run()
|
||||
|
||||
@ -4,6 +4,14 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type T struct{
|
||||
name string
|
||||
}
|
||||
func main() {
|
||||
fmt.Println(make(map[string]interface{}) == nil)
|
||||
var i interface{} = T{"john"}
|
||||
switch v := i.(type) {
|
||||
case T:
|
||||
default:
|
||||
fmt.Println(v)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user