Giter Site home page Giter Site logo

gogf / gf Goto Github PK

View Code? Open in Web Editor NEW
10.8K 214.0 1.5K 157.29 MB

GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang.

Home Page: https://goframe.org

License: MIT License

Go 99.94% Makefile 0.01% Shell 0.05%
framework session orm cache validator logger config template goframe go-framework

gf's People

Contributors

0xjayshen avatar 2892931976 avatar 564104865 avatar aloncn avatar ansionfor avatar chenyang351 avatar dguang21 avatar evil-king avatar giamyl avatar gqcn avatar hailaz avatar happyinsects avatar houseme avatar huangqian1985 avatar jianchenma avatar joy999 avatar jroam avatar kingeasternsun avatar lonelysally avatar mingzaily avatar oldme-git avatar qinyuguang avatar qinyuguang778 avatar shinxiang avatar stardemo avatar visualsun avatar wangle201210 avatar wenzi1 avatar wlynxg avatar zcool321 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gf's Issues

涉及tls的建议

httpclient,httpserver 虽然支持https,但是不能自定义tls的一些参数,比如信任ca,tls双向认证,证书校验,这些在很多安全要求高的领域都是必须的。其实给一个tls.Config设置的入口即可。另外HttpClient应该可以自定义设置tr,这样才能把HttpClient的方便性更好的发挥出来。

gvalid的checkStruct验证默认不会忽略私有成员,需要添加`structs:"-"`的tag

sms 包代码

package sms

type Message struct {
	Mobile     string `gvalid:"mobile@required#手机号必须"`
	Type       int    `gvalid:"type@required#消息类型必须"`
	Content    string
	TemplateId string `gvalid:"template_id@required-without:content#消息内容为空时,模板ID不能为空"`
	Param      string `gvalid:"param@required-with:template_id#模板ID存在时,参数不能为空"`
	config     map[string]interface{}
}

func NewMessage(mobile string, msgType int, content string, templateId string, param string) *Message {
	c := g.Config()
	_ = c.AddPath("config")
	conf := c.GetMap("miaodi")
	return &Message{
		Mobile:     mobile,
		Type:       msgType,
		Content:    content,
		TemplateId: templateId,
		Param:      param,
		config:     conf,
	}
}

main 包 代码

func main() {
	message := sms.NewMessage("123",1,"456","333","1,3,9")
	if e := gvalid.CheckStruct(message,nil); e != nil {
		g.Dump(e.Maps())
	}
}

报错

panic: reflect.Value.Interface: cannot return value obtained from unexported field or method

goroutine 1 [running]:
reflect.valueInterface(0x9c5a00, 0xc00020a908, 0x1b5, 0x1, 0xc000204bc8, 0x0)
	D:/Go/src/reflect/value.go:990 +0x1c6
reflect.Value.Interface(...)
	D:/Go/src/reflect/value.go:979
github.com/gogf/gf/third/github.com/fatih/structs.(*Field).Value(...)
	D:/gopath/pkg/mod/github.com/gogf/[email protected]/third/github.com/fatih/structs/field.go:31
github.com/gogf/gf/g/util/gvalid.CheckStruct(0x9e2ae0, 0xc00020a8c0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa6cd53)
	D:/gopath/pkg/mod/github.com/gogf/[email protected]/g/util/gvalid/gvalid_check_struct.go:64 +0x32e
main.main()
	D:/project/go/test/main.go:17 +0xb9

udp组件 的RemoteAddr对象方法获取不到客户端信息

func main() {
	gudp.NewServer("0.0.0.0:10243", func(conn *gudp.Conn) {
		defer conn.Close()
		for {
			if data, _ := conn.Recv(-1); len(data) > 0 {
				fmt.Println("RemoteAddr",conn.RemoteAddr())
				t := time.Now().Format("2006-01-02 15:04:05")
				fmt.Println(t,"recv:",string(data))
				conn.Send([]byte("got it"))

				//res, _ := conn.SendRecv([]byte(t), -1)
				//fmt.Println(string(res))
			}
		}
	}).Run()
}

当客户端建立连接时,需要获取客户端信息,使用了自带的RemoteAddr方法,却拿不到任何信息

数据库连接异常的处理

1. What version of Go are you using (go version)?

$ go version
1.11

2. What version of GoFrame are you using?

1.57

3. Does this issue reproduce with the latest release?

yes

4. What did you do?

       sqlDb, err = bs.db.Open(node)
        if err != nil {
            return nil
       }

项目启动的时候,数据库连接超时,没有任何的记录,依然能正常启动,结果web接口也不报错,状态为0,导致很难排查线上问题。

5. What did you expect to see?

应该给出日志,且项目终止启动;如果是运行的过程中db连接异常,应该给出日志,web接口应该给出500状态码

6. What did you see instead?

没有日志,接口状态码为0

gfsnotify在win10下无效?

package main

import (	
    "fmt"
    "gitee.com/johng/gf/g/os/gfsnotify"
)

func main() {

    err := gfsnotify.Add("C:/", func(event *gfsnotify.Event) {
        if event.IsCreate() {
            fmt.Println("创建文件 : ", event.Path)
        }
        if event.IsWrite() {
            fmt.Println("写入文件 : ", event.Path)
        }
        if event.IsRemove() {
            fmt.Println("删除文件 : ", event.Path)
        }
        if event.IsRename() {
            fmt.Println("重命名文件 : ", event.Path)
        }
        if event.IsChmod() {
            fmt.Println("修改权限 : ", event.Path)
        }
    })
    if err != nil {
        fmt.Println("遇到错误")
    } else {
        select {}
    }
}

以上代码基于官网文档修改的,把打印直接显示到屏幕上。但是运行后,没有任何显示。换其他目录操作,也一样。

struct中定义的xml标签在转xml时不起作用

使用gparser.VarToXmlIndent将struct转为xml时,struct中定义的TAG不起作用,例如:

type User struct {
	Name	string	`xml:"name" json:"name"`
	Age 	int		`xml:"bb" json:"dd" gconv:"aa"`
	Addr 	string	`xml:"cc"`
}

这个struct中Addr转为xml后标签本应为“cc”,但是实际结果为:

<user>
        <Addr>kaldsj</Addr>
        <aa>22</aa>
        <name>sss</name>
</user>

测试代码如下:

package main

import (
	"fmt"
	"github.com/gogf/gf/g/encoding/gparser"
)

type User struct {
	Name	string	`xml:"name" json:"name"`
	Age 	int		`xml:"bb" json:"dd" gconv:"aa"`
	Addr 	string	`xml:"cc"`
}
func main() {
	user := User{
		Name: "sss",
		Age: 22,
		Addr: "kaldsj",
	}

	xmlStr, err := gparser.VarToXmlIndent(user, "user")
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(string(xmlStr))
}

v1.5.8 binController("/",new(Controller.Index))代码不变生成路由会变动

1. What version of Go are you using (go version)?

$ go version
1.12

2. What version of GoFrame are you using?

1.5.8

3. Does this issue reproduce with the latest release?

no

4. What did you do?

升级前配置文件按文档设置,未变动。
注释控制器内部代码或者不注释不影响报错。
生成路由表每次编译有可能不生成,或者生成index方法的,或者index和user方法的都生成。
m 62d nzd7hlme1 mr f 1e
iou0de3ddo50n iux ej7nu
pmqp p72 f8l3 a6vgd6 za

怀疑bug,或者我路由注册方式有问题。不过升级前没出现过。

/router/router.go

func init() {
	// 用户模块 路由注册 - 使用执行对象注册方式
	s := g.Server()
	s.BindController("/", new(controller.Index))
}

/app/controller/index.go

type Index struct {
	gmvc.Controller
}

func (i *Index) Index() {
	//...
}

func (i *Index) User() {
	//...
}

5. What did you expect to see?

6. What did you see instead?

client 关闭时,server 无法接收到关闭请求

TCP 服务开发

1. What version of Go are you using (output of command: go version)?

$ go version
go 1.12

2. What version of GoFrame are you using?

v1.5.9

3. Can this issue be reproduced with the latest release?

4. What did you do?

当 client 结束进程时,server 并没有接收到任何消息。

	for {
			data, err := conn.Recv(-1)
			fmt.Println(string(data))
}

struct 查询有几个问题

struct 查询有几个问题

  1. 关键字 key 希望支持转成数据库的字段名,比如createAt 应该对应成 create_at
  2. 值 value ,么有过滤为空的情况
  3. 我的 struct 使用了继承 , 比如 base struct {id string} ,person struct{base}, 最后得到的 sql是 where base={id:333}

权拦拦截

package main

import (
	"fmt"
	"github.com/gogf/gf/g"
	"github.com/gogf/gf/g/net/ghttp"
	"github.com/gogf/gf/g/os/glog"
)

type UserController struct {
}

func (obj *UserController) Init(r *ghttp.Request) {
	fmt.Println("Init")
	Json(r, 0, "")
	r.ExitAll()
}

func (c *UserController) Find(r *ghttp.Request) {
	fmt.Println("Find")
	Json(r, 0, "")
}

func Json(r *ghttp.Request, err int, msg string, data ...interface{}) {
	responseData := interface{}(nil)
	if len(data) > 0 {
		responseData = data[0]
	}
	r.Response.WriteJson(g.Map{
		"err":  err,
		"msg":  msg,
		"data": responseData,
	})
	r.Exit()
}
func main() {
	s := g.Server()
	s.BindHookHandlerByMap("/user/*", map[string]ghttp.HandlerFunc{
		ghttp.HOOK_BEFORE_SERVE: func(r *ghttp.Request) {
			glog.Println(ghttp.HOOK_BEFORE_SERVE)
			Json(r, 0, "")
			r.ExitHook()
		},
		ghttp.HOOK_AFTER_SERVE:   func(r *ghttp.Request) { glog.Println(ghttp.HOOK_AFTER_SERVE) },
		ghttp.HOOK_BEFORE_OUTPUT: func(r *ghttp.Request) { glog.Println(ghttp.HOOK_BEFORE_OUTPUT) },
		ghttp.HOOK_AFTER_OUTPUT:  func(r *ghttp.Request) { glog.Println(ghttp.HOOK_AFTER_OUTPUT) },
		ghttp.HOOK_BEFORE_CLOSE:  func(r *ghttp.Request) { glog.Println(ghttp.HOOK_BEFORE_CLOSE) },
		ghttp.HOOK_AFTER_CLOSE:   func(r *ghttp.Request) { glog.Println(ghttp.HOOK_AFTER_CLOSE) },
	})
	s.BindObject("/user", new(UserController))
	s.SetPort(8888)
	s.Run()
}


测试

curl http://localhost:8888/user/find

测试结果

2019-02-25 15:43:05.877 54835: http server started listening on [:8888]
2019-02-25 15:43:05.877 [DEBU] GF notices that you're in develop environment, so error logs are auto enabled to stdout.

  SERVER  | ADDRESS | DOMAIN  | METHOD | P |   ROUTE    |           HANDLER           |     HOOK      
|---------|---------|---------|--------|---|------------|-----------------------------|--------------|
  default | :8888   | default | ALL    | 2 | /user/*    | main.main.func6             | AfterClose    
|---------|---------|---------|--------|---|------------|-----------------------------|--------------|
  default | :8888   | default | ALL    | 2 | /user/*    | main.main.func4             | AfterOutput   
|---------|---------|---------|--------|---|------------|-----------------------------|--------------|
  default | :8888   | default | ALL    | 2 | /user/*    | main.main.func2             | AfterServe    
|---------|---------|---------|--------|---|------------|-----------------------------|--------------|
  default | :8888   | default | ALL    | 2 | /user/*    | main.main.func5             | BeforeClose   
|---------|---------|---------|--------|---|------------|-----------------------------|--------------|
  default | :8888   | default | ALL    | 2 | /user/*    | main.main.func3             | BeforeOutput  
|---------|---------|---------|--------|---|------------|-----------------------------|--------------|
  default | :8888   | default | ALL    | 2 | /user/*    | main.main.func1             | BeforeServe   
|---------|---------|---------|--------|---|------------|-----------------------------|--------------|
  default | :8888   | default | ALL    | 2 | /user/find | main.(*UserController).Find |               
|---------|---------|---------|--------|---|------------|-----------------------------|--------------|

2019-02-25 15:43:59.947 BeforeServe
Init
Find
2019-02-25 15:43:59.948 AfterServe
2019-02-25 15:43:59.948 BeforeOutput
2019-02-25 15:43:59.948 AfterOutput
2019-02-25 15:43:59.948 BeforeClose
2019-02-25 15:43:59.948 AfterClose

期望,我想做权限的拦截,采用 jwt 的集成,目前遇到两个问题

  1. 按照文档说明, 在Init方法中执行 r.exit或者r.exitall,会停止后面的逻辑,但是测试不行,依旧会执行 find 方法
  2. 我希望在进入方式的时候就做拦截,使用 hook 方式, 在 BeforeServe 时候执行, r.exit或者r.exitall,会停止后面的逻辑,但是测试不行,依旧会执行 find 方法

gredis驱动的配置不支持timeout

1. What version of Go and system type/arch are you using?

2. What version of GoFrame are you using?

3. Can this issue be reproduced with the latest release?

4. What did you do?

5. What did you expect to see?

6. What did you see instead?

我需要搭建标准WebSocket服务,这个框架能实现吗?

1. What version of Go are you using (go version)?

go 1.12

$ go version

2. What version of GoFrame are you using?

最新版本

3. Does this issue reproduce with the latest release?

不确定

4. What did you do?

5. What did you expect to see?

我需要搭建标准WebSocket(SSL)服务,这个框架能实现吗?

6. What did you see instead?

关于数据查询结果集转Time类型错误

@johng-cn 你好,我update了你最新的代码,使用的是postgresql数据库,时间字段的数据库类型是timestamp,数据库查询结果集转Time类型还是错误,我看了你最新的源代码,应该是时间类型的模板以及正则的使用有问题、我将我的这个时间类型的字段转String,都是类似这样的数据,“2018-02-09T20:33:18.814Z“,”2018-02-09T20:46:17.897Z”,另外该功能是否所有数据库都能支持,请将此功能在做一下完整的测试,谢谢。

关于db初始化的问题

1. What version of Go and system type/arch are you using?

go 1.12 ubuntu18 64位

2. What version of GoFrame are you using?

1.5.16

3. Can this issue be reproduced with the latest release?

yes

4. What did you do?

a项目依赖gf,此项目为微服务的公共接口和model定义,只引用gf常见的工具;
b项目依赖gf,同时依赖b项目,但b项目启动的时候,db会初始化两次。

5. What did you expect to see?

希望db以及其他类似组件不要强制初始化,因为一个项目可能只想引用gf的工具集

6. What did you see instead?

conn.SendRecvWithTimeout()无法收到返回值,请问下如何解决?

    connections = gmap.New()
    connections是一个保存了conn的地图
    --------------------------------------------------
    conn := connections.Get(parkingNo)
if conn == nil {
	ResponseOK(c, "停车场未连接")
	return
}

    bytes := jsonutil.Marshal(request)
resBytes, err := conn.SendRecvWithTimeout(bytes, -1, 5*time.Second)
// 不会收到返回值,为什么
if err != nil {
	ResponseOK(c, err.Error())
	return
}

容器打包问题

基本信息

  • 版本1.5.0
  • 文档写的容器部署信息如下:
FROM loads/alpine:3.8

LABEL maintainer="[email protected]"

###############################################################################
#                                INSTALLATION
###############################################################################

ADD ./gf-app /bin/main
RUN chmod +x /bin/main

###############################################################################
#                                   START
###############################################################################

CMD main

问题描述

按照文档的那样写Dockerfile,因为没有指定CMD命令的所在目录,这样会默认在根目录/下。
这个时候代码配置如下配置文件目录

_ = c.AddPath("config")
_ = v.AddPath("template")

当程序启动的时候,就会添加//config/template三个目录到系统里面,但是程序还是会报找不到/config下的文件,例如:

2019-02-22 17:21:46.711 [DEBU] [gview] SetPath: /
2019-02-22 17:21:46.712 [DEBU] [gcfg] SetPath: /
2019-02-22 17:21:46.712 [DEBU] [gcfg] AddPath: /config
2019-02-22 17:21:46.712 [DEBU] [gview] AddPath: /template
2019-02-22 17:21:46.713 [ERRO] [gcfg] cannot find config file "config.toml" in following paths:
1. /
2. /config
Backtrace:
1. /Users/chenjingyang/go/pkg/mod/github.com/gogf/[email protected]/g/os/gcfg/gcfg.go:84
2. /Users/chenjingyang/go/pkg/mod/github.com/gogf/[email protected]/g/os/gcfg/gcfg.go:137
3. /Users/chenjingyang/go/pkg/mod/github.com/gogf/[email protected]/g/os/gcfg/gcfg.go:174
4. /Users/chenjingyang/go/pkg/mod/github.com/gogf/[email protected]/g/frame/gins/gins.go:117
5. /Users/chenjingyang/go/pkg/mod/github.com/gogf/[email protected]/g/container/gmap/gmap_string_interface_map.go:110
6. /Users/chenjingyang/go/pkg/mod/github.com/gogf/[email protected]/g/container/gmap/gmap_string_interface_map.go:137
7. /Users/chenjingyang/go/pkg/mod/github.com/gogf/[email protected]/g/frame/gins/gins.go:115
8. /Users/chenjingyang/go/pkg/mod/github.com/gogf/[email protected]/g/g_object.go:53
9. /Users/chenjingyang/go/src/code-generator/boot/boot.go:30

具体问题还需要作者排查,但是可以通过指定CMD的工作目录,问题就得以解决

解决方案

Dockerfile 修改为以下示例

FROM loads/alpine:3.8

LABEL maintainer="[email protected]"

###############################################################################
#                                INSTALLATION
###############################################################################

ADD ./gf-app /bin/main
RUN chmod +x /bin/main
RUN mkdir /root/config /root/template /root/public
COPY config/ /root/config
COPY template /root/template
###############################################################################
#                                   START
###############################################################################
WORKDIR /root
CMD main

这只是一个示例,一般不会使用root权限来执行容器里面的程序

批量绑定路由的时候index路径的问题

比方说,一般情况下注册路由,

server.bindController("/web",new(WebController))

此时,/web 或者/web/ 指向 Index方法。
而批量注册路由的情况下,/web或者/web/为not found,必须/web/index才能正确解析

关于协程池

限制最大的goroutine数量(Pool.size)变大后对已经加入队列的jobs(queue队列任务)不会重新分配PoolWorker。
相反,pool.size字段变小需要PoolWorker回收后才能真正的限制到协和数量。
不知道上面的情况是否是设计的初衷?

性能问题

被gf的路由注册、数据库record、自带很多常用的工具集等特点吸引过来,确实方便,花了几天时间打磨出一套快速开发平台,包括权限系统、代码生成的功能,目前也有几个系统在此平台运行。
由于系统涉及到高并发大流量的场景,我做了很多的压测,发现内存不断的增加,3种注册方式都测试过,函数注册、对象注册、控制器注册都试过,甚至函数注册逻辑只渲染一个简单的模板页面,最终结果都会导致内存不断增加,增加到2G之后我就没再做测试,等了数个小时之后,内存才降到200多M。
周末在家,我用gin实现了同样的功能,包括模板输出和json输出,在高并发的情况下,内存稳定在36M。
当然,gin用起来确实没有gf爽快,我希望作者给出内存不断增长的原因。

无法监听到客户端关闭的请求

如题,有特定的场景:
server <-> client 互发消息时,可以正常监听到 EOF。
但是当使用 manage -> server -> client,manage 通过 server 中转消息给 client 后,client 再关闭,这时 server 就无法监听到中断的 EOF 了。

我上三段代码:
server.go

package main

import (
	"fmt"
	"github.com/gogf/gf/g/encoding/gjson"
	"github.com/gogf/gf/g/net/gtcp"
	"github.com/gogf/gf/g/os/glog"
	"time"
)

var (
	myClients = map[*gtcp.Conn]string{}
)

func main() {
	gtcp.NewServer(":12345", func(conn *gtcp.Conn) {
		defer conn.Close()

		for {
			data, err := conn.Recv(-1)

			fmt.Println(string(data), err)
			if len(data) > 0 {
				if j, err := gjson.DecodeToJson(data); err != nil {
					glog.Error(err)
				} else {
					operate := j.GetString("operate")

					switch operate {
					case "register":
						uuid := j.GetString("uuid")
						myClients[conn] = uuid

						conn.Send(data)
						break

					case "anything":
						if j, err := gjson.DecodeToJson([]byte("{}")); err != nil {
							glog.Error(err)
						} else {
							j.Set("operate", "anything")
							j.Set("result", true)

							c, _ := j.ToJson()
							if err := conn.Send(c); err != nil {
								fmt.Println(err, "anything send error")
							}
						}
						break

					case "do_anything":
						uuid := j.GetString("uuid")

						if j, err := gjson.DecodeToJson([]byte("{}")); err != nil {
							glog.Error(err)
						} else {

							j.Set("operate", "do_anything")
							j.Set("timestamp", time.Now().Unix())
							c, _ := j.ToJson()

							for connect, uid := range myClients {
								fmt.Println(uid == uuid,uid,"<>",uuid)
								if uid == uuid {
									isSend := connect.Send(c)
									fmt.Println("send to " + uuid, isSend)
								}
							}
						}
						break

					case "stop":
						uuid := j.GetString("uuid")
						for connect, uid := range myClients {
							if uid == uuid {
								connect.Close()
								fmt.Println("close to " + uuid)
							}
						}
						break

					}

				}
			}

			if err != nil {
				fmt.Println(err, err.Error() == "EOF")

				//关闭终端则移除设备
				if err.Error() == "EOF" {
					fmt.Println(myClients[conn], "exist", myClients)
					if _, ok := myClients[conn]; ok {
						delete(myClients, conn)
						fmt.Println("remove")
					}
				}

				break
			}
		}
	}).Run()
}

client.go

package main

import (
	"fmt"
	"github.com/gogf/gf/g/encoding/gjson"
	"github.com/gogf/gf/g/net/gtcp"
	"github.com/gogf/gf/g/os/glog"
	"time"
)

func main() {
	message1 :=
		`{
	"operate":	"register",
	"uuid":	"123456789"
}`
	message2 :=
		`{
	"operate": "anything",
	"content": "content"
}`

	message := message1

	for {
		if conn, err := gtcp.NewPoolConn("127.0.0.1:12345"); err == nil {
			if b, err := conn.SendRecv([]byte(message), -1); err == nil {
				fmt.Println(string(b), conn.LocalAddr(), conn.RemoteAddr())

				if j, err := gjson.DecodeToJson(b); err != nil {
					glog.Error(err)
				} else {
					operate := j.GetString("operate")
					if operate == "register" {
						message = message2
					}
				}
			} else {
				glog.Error(err)

				if err.Error() == "EOF" {
					break
				}
			}
			conn.Close()
		} else {
			glog.Error(err)

			break
		}
		time.Sleep(time.Second * 5)
	}
}

manage.go

package main

import (
	"github.com/gogf/gf/g/net/gtcp"
	"github.com/gogf/gf/g/os/glog"
)

func main() {

	//"460010100000011", "460010100000012"
	message3 := `{"operate": "do_anything", "uuid": "123456789"}`

	message4 := `{"operate": "stop", "uuid": "123456789"}`

	var message string
	message = message4
	message = message3

	if conn, err := gtcp.NewConn("127.0.0.1:12345"); err == nil {
		err := conn.Send([]byte(message))
		if err != nil {
			glog.Error(err)
		}
		conn.Close()
	} else {
		glog.Error(err)
	}
}

服务端
image

客户端
image

管理端
go run manage.go

报错是

read tcp 127.0.0.1:12345->127.0.0.1:51803: read: connection reset by peer
read tcp 127.0.0.1:12345->127.0.0.1:51803: read: connection reset by peer false

控制器基类shut方法定义错误

控制器基类里面这样定义Shut
func (c *Controller) Shut() ,https://github.com/gogf/gf/blob/master/g/frame/gmvc/controller.go#L35
但是注册方法里面却这样转换,fshut = v.MethodByName("Shut").Interface().(func(*Request))
https://github.com/gogf/gf/blob/master/g/net/ghttp/ghttp_server_service_object.go#L40
导致继承基类的控制器都不能注册,会报pnaic错误,类型转换错误,
panic: interface conversion: interface {} is func(), not func(*ghttp.Request)

gdb 跟其它orm一样用的reflect实现的吗?

1. What version of Go and system type/arch are you using?

2. What version of GoFrame are you using?

3. Can this issue be reproduced with the latest release?

4. What did you do?

5. What did you expect to see?

6. What did you see instead?

输出不了json

`type DemoInfo struct {
Name string
Age string
}

l := map[interface{}][]DemoInfo{}

el := [...]DemoInfo{
	{Name:"Bala", Age:"15"},
	{Name:"CeCe", Age:"18"},
	{Name:"ChenLo", Age:"28"},
	{Name:"Bii", Age:"22"},
	{Name:"Ann", Age:"23"},
	{Name:"Bmx", Age:"88"},
}
fmt.Println(el)

for _,v := range el{
	l[string(v.Name[0])] = append(l[string(v.Name[0])],v)
}
fmt.Println(l)

c.Response.WriteJson(l)`

静态html文件不是utf8格式情况下,乱码问题

静态文件服务器,打开的文件是utf-8能正常显示,若文件编码是ANSI格式,打开后就是乱码。
如静态html文件,ansi格式保存:
meta http-equiv="Content-Type" content="text/html; charset=gb2312"

<title>金蝶EAS用户手册丛书---参考指南</title>

package main
import (
"github.com/gogf/gf/g"
)
func main(){
s := g.Server()
s.SetIndexFolder(true)
s.SetServerRoot("C:\ HTML版")
s.Run()
}

注:另外go内置的静态文件服务器也是上述情况(乱码)。

建议gdb增加GetLastSql()方法

建议gdb增加GetLastSql()方法

新增加方法希望能实现:获取最近执行的完整的sql语句字符串.

如下:
`
rs,_:=db.Table("cd_orderform").Where("title like '九寨%'").OrderBy("orderform0 desc").Limit(0,3).Select()

sqls:=db.GetLastSql()

fmt.Println(sqls) // print : select * from cd_orderform where title like '九寨%' order by orderform0 desc limit 0,3
`

这样在开发时,对排查问题,很有帮助。

ajax 请求缺少头部设置

ajax 希望增加 Access-Control-Allow-Headers 的设置, 支持对Authorization的认证方式

我现在是这么做的

r.Response.Header().Set("Access-Control-Allow-Headers", "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization")

除了查询,其它插入、更新都不行

package main

import (
	"gitee.com/johng/gf/g/database/gdb"
	"fmt"
)

var db *gdb.Db

func init()  {
	gdb.AddDefaultConfigNode(gdb.ConfigNode {
		Host    : "127.0.0.1",
		Port    : "3306",
		User    : "root",
		Pass    : "123456",
		Name    : "test",
		Type    : "mysql",
		Role    : "master",
		Charset : "utf8",
	})
	var err error
	db, err = gdb.Instance()
	checkErr(err)
}

func main() {
	query()
	insert()
}

// 基本sql查询
func query() {
	fmt.Println("query:")
	list, err := db.GetAll("select * from user limit 2")
	if err == nil {
		fmt.Println(list)
	} else {
		fmt.Println(err)
	}
	fmt.Println()
}

// 数据写入
func insert() {
	fmt.Println("insert:")
	r, err := db.Insert("user", gdb.Map {
		"name": "john",
	})
	if err == nil {
		uid, _ := r.LastInsertId()
		fmt.Println(uid)
	} else {
		fmt.Println(err)
	}
	fmt.Println()
}

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}

输出如下:

query:
[map[email:[email protected] type:1 uid:1 name:take] map[uid:14 name:flume email:[email protected] type:1]]

insert:
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0xf0 pc=0x60bb92]

goroutine 1 [running]:
gitee.com/johng/gf/g/database/gdb.(*Db).Exec(0xc04203e200, 0xc042064870, 0x21, 0xc042036c40, 0x1, 0x1, 0x21, 0x1, 0x4, 0x0)
        D:/Goworks/src/gitee.com/johng/gf/g/database/gdb/gdb_base.go:51 +0x72
gitee.com/johng/gf/g/database/gdb.(*Db).insert(0xc04203e200, 0x68db07, 0x4, 0xc042064840, 0xc042072400, 0x0, 0x0, 0x0, 0x0)
        D:/Goworks/src/gitee.com/johng/gf/g/database/gdb/gdb_base.go:205 +0xc34
gitee.com/johng/gf/g/database/gdb.(*Db).Insert(0xc04203e280, 0x68db07, 0x4, 0xc042064840, 0xc042064840, 0x0, 0x0, 0x0)
        D:/Goworks/src/gitee.com/johng/gf/g/database/gdb/gdb_base.go:210 +0x64
main.insert()
        D:/Goworks/src/edition/b.go:48 +0x1d4
main.main()
        D:/Goworks/src/edition/b.go:28 +0x2c
exit status 2

user表结构:

CREATE TABLE `user` (
  `uid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL DEFAULT '' COMMENT '昵称',
  `email` varchar(60) NOT NULL DEFAULT '' COMMENT '邮箱',
  `type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '订单',
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

当新建文件时,必须要判断文件是否存在才能读出内容,否则读取为空

package main

import (
"fmt"
"gitee.com/johng/gf/g"
"gitee.com/johng/gf/g/os/gfile"
"gitee.com/johng/gf/g/os/gfsnotify"
"gitee.com/johng/gf/g/os/glog"
)

func main() {
// /home/john/temp 是一个目录,当然也可以指定文件
paths:=g.Config().GetFilePath()
fmt.Println("=====",paths)
path := "/ftpDic"
_, err := gfsnotify.Add(path, func(event *gfsnotify.Event) {
if event.IsCreate() {
glog.Println("创建文件 : ", event.Path)
}
if event.IsWrite() {
glog.Println("写入文件 : ", event.Path)
if gfile.Exists(event.Path) {
fmt.Printf("%s\n", gfile.GetContents(event.Path))
}
//gfile.GetContents()
}
if event.IsRemove() {
glog.Println("删除文件 : ", event.Path)
}
if event.IsRename() {
glog.Println("重命名文件 : ", event.Path)
}
if event.IsChmod() {
glog.Println("修改权限 : ", event.Path)
}

	glog.Println(event)
})

// 移除对该path的监听
// gfsnotify.Remove(path)

if err != nil {
	glog.Fatal(err)
} else {
	select {}
}

}

请求404的问题

在1.5.2版本中,不存在的路由,页面依然返回200状态码,自动注册的404无效;
经查,ghttp_server_handler.go文件中的一次commit,

if len(request.Response.Header()) == 0 &&
     request.Response.Status == 0 &&
     request.Response.BufferLength() == 0 {
     request.Response.WriteStatus(http.StatusNotFound)
}

跟进上面的response,发现

// 创建请求处理对象
    request := newRequest(s, r, w)
r := &Response {
        Server         : s,
        ResponseWriter : ResponseWriter {
            ResponseWriter : w,
            Status         : http.StatusOK,
            buffer         : bytes.NewBuffer(nil),
        },
    }
    r.Writer = &r.ResponseWriter
    return r

response状态码初始化为200,所以永远不会进入if方法,导致不会产生404错误,请作者看看我的分析是否正确

模版热更新有问题

模版热更新有问题,多次修改html模版并刷新页面,会出现空白页面的情况

全局跨域设置

目前我知道可以通过Hook回调事件设置跨域
有没有配置参数全局设置呢?或者是针对特定路由设置

事务操作只支持一条语句?

文档代码:

if tx, err := db.Begin(); err == nil {
    r, err := tx.Table("user").Data(gdb.Map{"uid":1, "name": "john_1"}).Save()
    tx.Commit()
    fmt.Println(r, err)
}

在使用过程中多进行一条语句操作,事务就不生效了:

if tx, err := db.Begin(); err == nil {
    r, err := tx.Table("user").Data(gdb.Map{"uid":1, "name": "john_1"}).Save()
    rd, errd := tx.Table("user").Where("uid=?",2).Delete()
    tx.Commit()
    fmt.Println(r, err)
    fmt.Println(rd, errd)
}

文档中也没有找到相关的介绍,不知道这是框架的机制还是我使用不正确造成的,还望大神回复一下。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.