完善并改进gbinary,gconv包类型转换功能,改进ghttp.Response对象操作

This commit is contained in:
John
2018-04-14 01:05:46 +08:00
parent e84420f894
commit 2979b64668
8 changed files with 228 additions and 119 deletions

8
TODO
View File

@ -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请求执行中增加服务退出的方法不再执行后续操作

View File

@ -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长度

View File

@ -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
}

View File

@ -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()
}

View File

@ -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)
}

View File

@ -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))
}

View File

@ -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()

View File

@ -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)
}
}