Compare commits

..

8 Commits

24 changed files with 131 additions and 65 deletions

View File

@ -85,7 +85,8 @@ func New(config Config) *Redis {
}
return c, nil
},
// 用来测试连接是否可用
// 在被应用从连接池中获取出来之后,用以测试连接是否可用
// 如果返回error那么关闭该连接对象重新创建新的连接。
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
return err

View File

@ -81,28 +81,29 @@ func (r *Request) GetVar(key string, def ... interface{}) gvar.VarRead {
// 获取原始请求输入二进制。
func (r *Request) GetRaw() []byte {
err := error(nil)
if r.rawContent == nil {
r.rawContent, _ = ioutil.ReadAll(r.Body)
r.rawContent, err = ioutil.ReadAll(r.Body)
if err != nil {
r.Error("error reading request body: ", err)
}
}
return r.rawContent
}
// 获取原始请求输入字符串。
func (r *Request) GetRawString() string {
if r.rawContent == nil {
r.rawContent, _ = ioutil.ReadAll(r.Body)
}
return string(r.rawContent)
return string(r.GetRaw())
}
// 获取原始json请求输入字符串并解析为json对象
func (r *Request) GetJson() *gjson.Json {
data := r.GetRaw()
if data != nil {
if len(data) > 0 {
if j, err := gjson.DecodeToJson(data); err == nil {
return j
} else {
panic(err)
r.Error(err, ": ", string(data))
}
}
return nil

View File

@ -26,21 +26,21 @@ func (r *Request) setBasicAuth(tips...string) {
}
// 设置HTTP基础账号密码认证如果用户没有提交账号密码那么提示用户输出信息。
// 验证成功之后返回true否则返回false
// 验证成功之后返回true否则返回false
func (r *Request) BasicAuth(user, pass string, tips...string) bool {
auth := r.Header.Get("Authorization")
if auth == "" {
r.setBasicAuth(tips...)
return false
}
auths := strings.SplitN(auth, " ", 2)
if len(auths) != 2 {
authArray := strings.SplitN(auth, " ", 2)
if len(authArray) != 2 {
r.Response.WriteStatus(http.StatusForbidden)
return false
}
switch auths[0] {
switch authArray[0] {
case "Basic":
authStr, err := gbase64.Decode(auths[1])
authStr, err := gbase64.Decode(authArray[1])
if err != nil {
r.Response.WriteStatus(http.StatusForbidden, err.Error())
return false
@ -54,11 +54,12 @@ func (r *Request) BasicAuth(user, pass string, tips...string) bool {
r.setBasicAuth(tips...)
return false
}
return true
default:
r.Response.WriteStatus(http.StatusForbidden)
return false
}
return true
return false
}

View File

@ -0,0 +1,14 @@
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package ghttp
import "fmt"
// 打印error日志
func (r *Request) Error(value... interface{}) {
r.Server.handleErrorLog(fmt.Sprint(value...), r)
}

View File

@ -169,7 +169,7 @@ func (r *Request) GetPostMap(def...map[string]string) map[string]string {
}
// 将所有的request参数映射到struct属性上参数object应当为一个struct对象的指针, mapping为非必需参数自定义参数与属性的映射关系
func (r *Request) GetPostToStruct(object interface{}, mapping...map[string]string) {
func (r *Request) GetPostToStruct(object interface{}, mapping...map[string]string) error {
tagmap := r.getStructParamsTagMap(object)
if len(mapping) > 0 {
for k, v := range mapping[0] {
@ -180,5 +180,5 @@ func (r *Request) GetPostToStruct(object interface{}, mapping...map[string]strin
for k, v := range r.GetPostMap() {
params[k] = v
}
gconv.Struct(params, object, tagmap)
return gconv.Struct(params, object, tagmap)
}

View File

@ -177,7 +177,7 @@ func (r *Request) GetQueryMap(def ... map[string]string) map[string]string {
}
// 将所有的get参数映射到struct属性上参数object应当为一个struct对象的指针, mapping为非必需参数自定义参数与属性的映射关系
func (r *Request) GetQueryToStruct(object interface{}, mapping...map[string]string) {
func (r *Request) GetQueryToStruct(object interface{}, mapping...map[string]string) error {
tagmap := r.getStructParamsTagMap(object)
if len(mapping) > 0 {
for k, v := range mapping[0] {
@ -188,5 +188,5 @@ func (r *Request) GetQueryToStruct(object interface{}, mapping...map[string]stri
for k, v := range r.GetQueryMap() {
params[k] = v
}
gconv.Struct(params, object, tagmap)
return gconv.Struct(params, object, tagmap)
}

View File

@ -162,7 +162,7 @@ func (r *Request) GetRequestMap(def...map[string]string) map[string]string {
}
// 将所有的request参数映射到struct属性上参数object应当为一个struct对象的指针, mapping为非必需参数自定义参数与属性的映射关系
func (r *Request) GetRequestToStruct(object interface{}, mapping...map[string]string) {
func (r *Request) GetRequestToStruct(object interface{}, mapping...map[string]string) error {
tagmap := r.getStructParamsTagMap(object)
if len(mapping) > 0 {
for k, v := range mapping[0] {
@ -178,6 +178,6 @@ func (r *Request) GetRequestToStruct(object interface{}, mapping...map[string]st
params = j.ToMap()
}
}
gconv.Struct(params, object, tagmap)
return gconv.Struct(params, object, tagmap)
}

View File

@ -350,7 +350,10 @@ func (s *Server) GetRouteMap() string {
}
addr := s.config.Addr
if s.config.HTTPSAddr != "" {
addr += ",tls" + s.config.HTTPSAddr
if len(addr) > 0 {
addr += ","
}
addr += "tls" + s.config.HTTPSAddr
}
for _, a := range m {
data := make([]string, 8)

View File

@ -10,6 +10,7 @@ package ghttp
import (
"fmt"
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/os/gtime"
)
// 处理服务错误信息主要是panichttp请求的status由access log进行管理
@ -46,7 +47,11 @@ func (s *Server) handleErrorLog(error interface{}, r *Request) {
// 错误日志信息
content := fmt.Sprintf(`%v, "%s %s %s %s"`, error, r.Method, r.Host, r.URL.String(), r.Proto)
content += fmt.Sprintf(` %.3f`, float64(r.LeaveTime - r.EnterTime)/1000)
if r.LeaveTime > r.EnterTime {
content += fmt.Sprintf(` %.3f`, float64(r.LeaveTime - r.EnterTime)/1000)
} else {
content += fmt.Sprintf(` %.3f`, float64(gtime.Microsecond() - r.EnterTime)/1000)
}
content += fmt.Sprintf(`, %s, "%s", "%s"`, r.GetClientIp(), r.Referer(), r.UserAgent())
if s.logger.GetPath() == "" {

View File

@ -176,11 +176,11 @@ func (c *Config) getJson(file...string) *gjson.Json {
j.SetViolenceCheck(c.vc.Val())
// 添加配置文件监听,如果有任何变化,删除文件内容缓存,下一次查询会自动更新
gfsnotify.Add(filePath, func(event *gfsnotify.Event) {
c.jsons.Remove(event.Path)
c.jsons.Remove(name)
})
return j
} else {
glog.Errorfln(`[gcfg] Load config file "%s" failed: %s`, filePath, err.Error())
glog.Criticalfln(`[gcfg] Load config file "%s" failed: %s`, filePath, err.Error())
}
return nil
})

View File

@ -8,6 +8,7 @@ package gconv
import (
"github.com/gogf/gf/g/internal/empty"
"github.com/gogf/gf/g/text/gstr"
"reflect"
"strings"
)
@ -102,6 +103,11 @@ func Map(value interface{}, noTagCheck...bool) map[string]interface{} {
rt := rv.Type()
name := ""
for i := 0; i < rv.NumField(); i++ {
// 只转换公开属性
fieldName := rt.Field(i).Name
if !gstr.IsLetterUpper(fieldName[0]) {
continue
}
name = ""
// 检查tag, 支持gconv, json标签, 优先使用gconv
if len(noTagCheck) == 0 || !noTagCheck[0] {
@ -111,7 +117,7 @@ func Map(value interface{}, noTagCheck...bool) map[string]interface{} {
}
}
if name == "" {
name = strings.TrimSpace(rt.Field(i).Name)
name = strings.TrimSpace(fieldName)
} else {
// 支持标准库json特性: -, omitempty
name = strings.TrimSpace(name)

View File

@ -7,6 +7,7 @@
package gconv
import (
"github.com/gogf/gf/g/text/gstr"
"reflect"
)
@ -311,7 +312,12 @@ func Interfaces(i interface{}) []interface{} {
array = append(array, rv.Index(i).Interface())
}
case reflect.Struct:
rt := rv.Type()
for i := 0; i < rv.NumField(); i++ {
// 只获取公开属性
if !gstr.IsLetterUpper(rt.Field(i).Name[0]) {
continue
}
array = append(array, rv.Field(i).Interface())
}
default:

View File

@ -78,6 +78,10 @@ func Struct(params interface{}, objPointer interface{}, attrMapping...map[string
attrMap := make(map[string]struct{})
elemType := elem.Type()
for i := 0; i < elem.NumField(); i++ {
// 只转换公开属性
if !gstr.IsLetterUpper(elemType.Field(i).Name[0]) {
continue
}
attrMap[elemType.Field(i).Name] = struct{}{}
}
for mapK, mapV := range paramsMap {

View File

@ -112,3 +112,15 @@ func Test_Map_StructWithJsonTag(t *testing.T) {
gtest.Assert(map2["password2"], "456")
})
}
// 私有属性不会进行转换
func Test_Map_PrivateAttribute(t *testing.T) {
type User struct {
Id int
name string
}
gtest.Case(t, func() {
user := &User{1, "john"}
gtest.Assert(gconv.Map(user), g.Map{"Id" : 1})
})
}

View File

@ -7,6 +7,7 @@
package gconv_test
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g/test/gtest"
"testing"
@ -23,3 +24,15 @@ func Test_Slice(t *testing.T) {
gtest.AssertEQ(gconv.Interfaces(value), []interface{}{123.456})
})
}
// 私有属性不会进行转换
func Test_Slice_PrivateAttribute(t *testing.T) {
type User struct {
Id int
name string
}
gtest.Case(t, func() {
user := &User{1, "john"}
gtest.Assert(gconv.Interfaces(user), g.Slice{1})
})
}

View File

@ -8,12 +8,11 @@ package gconv_test
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g/test/gtest"
"github.com/gogf/gf/g/util/gconv"
"testing"
)
func Test_Struct_Basic1(t *testing.T) {
gtest.Case(t, func() {
type User struct {
@ -302,3 +301,18 @@ func Test_Struct_Attr_Struct_Slice_Ptr(t *testing.T) {
}
})
}
// 私有属性不会进行转换
func Test_Struct_PrivateAttribute(t *testing.T) {
type User struct {
Id int
name string
}
gtest.Case(t, func() {
user := new(User)
err := gconv.Struct(g.Map{"id" : 1, "name" : "john"}, user)
gtest.Assert(err, nil)
gtest.Assert(user.Id, 1)
gtest.Assert(user.name, "")
})
}

View File

@ -7,6 +7,7 @@
package gvalid
import (
"github.com/gogf/gf/g/text/gstr"
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/third/github.com/fatih/structs"
"strings"
@ -59,14 +60,19 @@ func CheckStruct(object interface{}, rules interface{}, msgs...CustomMsg) *Error
case map[string]string:
checkRules = v
}
// 首先, 按照属性循环一遍将strcut的属性、数值、tag解析
// 首先, 按照属性循环一遍将struct的属性、数值、tag解析
for _, field := range fields {
params[field.Name()] = field.Value()
fieldName := field.Name()
// 只检测公开属性
if !gstr.IsLetterUpper(fieldName[0]) {
continue
}
params[fieldName] = field.Value()
if tag := field.Tag("gvalid"); tag != "" {
// sequence tag == struct tag, 这里的name为别名
name, rule, msg := parseSequenceTag(tag)
if len(name) == 0 {
name = field.Name()
name = fieldName
}
// params参数使用别名**扩容**(而不仅仅使用别名),仅用于验证使用
if _, ok := params[name]; !ok {
@ -151,3 +157,4 @@ func CheckStruct(object interface{}, rules interface{}, msgs...CustomMsg) *Error
}
return nil
}

View File

@ -16,4 +16,5 @@ func main() {
redis.Do("SET", "k", "v")
v, _ := redis.Do("GET", "k")
fmt.Println(gconv.String(v))
}
}

View File

@ -1,25 +0,0 @@
package main
import (
"net/http"
"github.com/gogf/gf/g/net/ghttp"
)
func main() {
s := ghttp.GetServer()
s.BindHandler("/log/handler", func(r *ghttp.Request){
r.Response.WriteStatus(http.StatusNotFound, "文件找不到了")
})
s.SetAccessLogEnabled(true)
s.SetErrorLogEnabled(true)
//s.SetLogHandler(func(r *ghttp.Request, error ...interface{}) {
// if len(error) > 0 {
// // 如果是错误日志
// fmt.Println("错误产生了:", error[0])
// }
// // 这里是请求日志
// fmt.Println("请求处理完成,请求地址:", r.URL.String(), "请求结果:", r.Response.Status)
//})
s.SetPort(8199)
s.Run()
}

View File

@ -35,7 +35,7 @@
}
$(function () {
var url = "ws://127.0.0.1:8199/ws";
var url = "wss://127.0.0.1:8199/wss";
var ws = new WebSocket(url);
try {
// ws连接成功

View File

@ -3,12 +3,13 @@ package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/os/glog"
)
func main() {
s := g.Server()
s.BindHandler("/ws", func(r *ghttp.Request) {
s.BindHandler("/wss", func(r *ghttp.Request) {
ws, err := r.WebSocket()
if err != nil {
glog.Error(err)
@ -24,6 +25,8 @@ func main() {
}
}
})
s.SetServerRoot(gfile.MainPkgPath())
s.EnableHTTPS("../../https/server.crt", "../../https/server.key")
s.SetPort(8199)
s.Run()
}

View File

@ -3,6 +3,7 @@ package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/os/glog"
)
@ -24,6 +25,7 @@ func main() {
}
}
})
s.SetServerRoot(gfile.MainPkgPath())
s.SetPort(8199)
s.Run()
}

View File

@ -1,13 +1,11 @@
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/text/gregex"
"encoding/json"
"fmt"
)
func main() {
s := "127.0.0.1:6379,1,nhytaf176tg?maxIdle=1&maxActive=0&idleTimeout=60&maxConnLifetime=60"
array, err := gregex.MatchString(`(.+):(\d+),{0,1}(\d*),{0,1}(.*)\?(.+)`, s)
g.Dump(err)
g.Dump(array)
fmt.Println(json.Valid([]byte("111")))
}

View File

@ -1,5 +1,5 @@
package gf
const VERSION = "v1.5.18"
const VERSION = "v1.5.20"
const AUTHORS = "john<john@goframe.org>"