mirror of
https://gitee.com/johng/gf
synced 2026-06-20 23:29:27 +08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9797701881 | |||
| 8a50b180c0 | |||
| 159190d187 | |||
| 989d543a1f | |||
| fcc3a1b2f6 |
@ -14,13 +14,13 @@
|
||||
[](https://www.codetriage.com/gogf/gf)
|
||||
-->
|
||||
|
||||
`GF(GoFrame)` is a modular, lightweight, loosely coupled, high performance application development framework written in Go. Supporting graceful server, hot updates, multi-domain, multi-port, multi-service, HTTP/HTTPS, dynamic/hook routing and many more features. Providing a series of core components and dozens of practical modules.
|
||||
`GF(GoFrame)` is a modular, loose-coupled and production-ready application development framework written in Go. Providing a series of core components and dozens of practical modules, such as: cache, logging, array/queue/set/map, timer/timing tasks, file/memory lock, object pool, validator, database ORM, etc. Supporting web server with graceful server, hot updates, multi-domain, multi-port, multi-service, HTTP/HTTPS, dynamic/hook routing, rewrite rules and many more features.
|
||||
|
||||
# Installation
|
||||
```
|
||||
go get -u github.com/gogf/gf
|
||||
```
|
||||
or use `go.mod`
|
||||
or use `go.mod`:
|
||||
```
|
||||
require github.com/gogf/gf latest
|
||||
```
|
||||
@ -32,6 +32,7 @@ golang version >= 1.9.2
|
||||
|
||||
# Documentation
|
||||
|
||||
* [GoDoc](https://godoc.org/github.com/gogf/gf)
|
||||
* [中文文档](https://goframe.org)
|
||||
|
||||
# Architecture
|
||||
@ -92,6 +93,8 @@ func main() {
|
||||
|
||||
# Donators
|
||||
|
||||
<a href="https://gitee.com/tiangenglan" target="_blank" title="zhuhuan12"><img src="https://images.gitee.com/uploads/99/1167099_tiangenglan.png" width="60" align="left"></a>
|
||||
|
||||
<a href="https://gitee.com/zhuhuan12" target="_blank" title="zhuhuan12"><img src="https://gitee.com/uploads/39/751839_zhuhuan12.png" width="60" align="left"></a>
|
||||
|
||||
<a href="https://gitee.com/zfan_codes" target="_blank" title="范钟"><img src="https://images.gitee.com/uploads/32/2044832_zfan_codes.png" width="60" align="left"></a>
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
go get -u github.com/gogf/gf
|
||||
```
|
||||
或者
|
||||
`go.mod`
|
||||
`go.mod`:
|
||||
```
|
||||
require github.com/gogf/gf latest
|
||||
```
|
||||
@ -100,6 +100,8 @@ func main() {
|
||||
|
||||
# 捐赠者
|
||||
|
||||
<a href="https://gitee.com/tiangenglan" target="_blank" title="zhuhuan12"><img src="https://images.gitee.com/uploads/99/1167099_tiangenglan.png" width="60" align="left"></a>
|
||||
|
||||
<a href="https://gitee.com/zhuhuan12" target="_blank" title="zhuhuan12"><img src="https://gitee.com/uploads/39/751839_zhuhuan12.png" width="60" align="left"></a>
|
||||
|
||||
<a href="https://gitee.com/zfan_codes" target="_blank" title="范钟"><img src="https://images.gitee.com/uploads/32/2044832_zfan_codes.png" width="60" align="left"></a>
|
||||
|
||||
@ -9,44 +9,44 @@
|
||||
package ghttp
|
||||
|
||||
func Get(url string) (*ClientResponse, error) {
|
||||
return DoRequest("GET", url, []byte(""))
|
||||
return DoRequest("GET", url)
|
||||
}
|
||||
|
||||
func Put(url, data string) (*ClientResponse, error) {
|
||||
return DoRequest("PUT", url, []byte(data))
|
||||
func Put(url string, data...string) (*ClientResponse, error) {
|
||||
return DoRequest("PUT", url, data...)
|
||||
}
|
||||
|
||||
func Post(url, data string) (*ClientResponse, error) {
|
||||
return DoRequest("POST", url, []byte(data))
|
||||
func Post(url string, data...string) (*ClientResponse, error) {
|
||||
return DoRequest("POST", url, data...)
|
||||
}
|
||||
|
||||
func Delete(url, data string) (*ClientResponse, error) {
|
||||
return DoRequest("DELETE", url, []byte(data))
|
||||
func Delete(url string, data...string) (*ClientResponse, error) {
|
||||
return DoRequest("DELETE", url, data...)
|
||||
}
|
||||
|
||||
func Head(url, data string) (*ClientResponse, error) {
|
||||
return DoRequest("HEAD", url, []byte(data))
|
||||
func Head(url string, data...string) (*ClientResponse, error) {
|
||||
return DoRequest("HEAD", url, data...)
|
||||
}
|
||||
|
||||
func Patch(url, data string) (*ClientResponse, error) {
|
||||
return DoRequest("PATCH", url, []byte(data))
|
||||
func Patch(url string, data...string) (*ClientResponse, error) {
|
||||
return DoRequest("PATCH", url, data...)
|
||||
}
|
||||
|
||||
func Connect(url, data string) (*ClientResponse, error) {
|
||||
return DoRequest("CONNECT", url, []byte(data))
|
||||
func Connect(url string, data...string) (*ClientResponse, error) {
|
||||
return DoRequest("CONNECT", url, data...)
|
||||
}
|
||||
|
||||
func Options(url, data string) (*ClientResponse, error) {
|
||||
return DoRequest("OPTIONS", url, []byte(data))
|
||||
func Options(url string, data...string) (*ClientResponse, error) {
|
||||
return DoRequest("OPTIONS", url, data...)
|
||||
}
|
||||
|
||||
func Trace(url, data string) (*ClientResponse, error) {
|
||||
return DoRequest("TRACE", url, []byte(data))
|
||||
func Trace(url string, data...string) (*ClientResponse, error) {
|
||||
return DoRequest("TRACE", url, data...)
|
||||
}
|
||||
|
||||
// 该方法支持二进制提交数据
|
||||
func DoRequest(method, url string, data []byte) (*ClientResponse, error) {
|
||||
return NewClient().DoRequest(method, url, data)
|
||||
func DoRequest(method, url string, data...string) (*ClientResponse, error) {
|
||||
return NewClient().DoRequest(method, url, data...)
|
||||
}
|
||||
|
||||
// GET请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
|
||||
@ -76,26 +76,30 @@ func (c *Client) SetBasicAuth(user, pass string) {
|
||||
|
||||
// GET请求
|
||||
func (c *Client) Get(url string) (*ClientResponse, error) {
|
||||
return c.DoRequest("GET", url, []byte(""))
|
||||
return c.DoRequest("GET", url)
|
||||
}
|
||||
|
||||
// PUT请求
|
||||
func (c *Client) Put(url, data string) (*ClientResponse, error) {
|
||||
return c.DoRequest("PUT", url, []byte(data))
|
||||
func (c *Client) Put(url string, data...string) (*ClientResponse, error) {
|
||||
return c.DoRequest("PUT", url, data...)
|
||||
}
|
||||
|
||||
// POST请求提交数据,默认使用表单方式提交数据(绝大部分场景下也是如此)。
|
||||
// 如果服务端对Content-Type有要求,可使用Client对象进行请求,单独设置相关属性。
|
||||
// 支持文件上传,需要字段格式为:FieldName=@file:
|
||||
func (c *Client) Post(url, data string) (*ClientResponse, error) {
|
||||
func (c *Client) Post(url string, data...string) (*ClientResponse, error) {
|
||||
if len(c.prefix) > 0 {
|
||||
url = c.prefix + url
|
||||
}
|
||||
param := ""
|
||||
if len(data) > 0 {
|
||||
param = data[0]
|
||||
}
|
||||
req := (*http.Request)(nil)
|
||||
if strings.Contains(data, "@file:") {
|
||||
if strings.Contains(param, "@file:") {
|
||||
buffer := new(bytes.Buffer)
|
||||
writer := multipart.NewWriter(buffer)
|
||||
for _, item := range strings.Split(data, "&") {
|
||||
for _, item := range strings.Split(param, "&") {
|
||||
array := strings.Split(item, "=")
|
||||
if len(array[1]) > 6 && strings.Compare(array[1][0:6], "@file:") == 0 {
|
||||
path := array[1][6:]
|
||||
@ -126,7 +130,7 @@ func (c *Client) Post(url, data string) (*ClientResponse, error) {
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
}
|
||||
} else {
|
||||
if r, err := http.NewRequest("POST", url, bytes.NewReader([]byte(data))); err != nil {
|
||||
if r, err := http.NewRequest("POST", url, bytes.NewReader([]byte(param))); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
req = r
|
||||
@ -154,28 +158,28 @@ func (c *Client) Post(url, data string) (*ClientResponse, error) {
|
||||
}
|
||||
|
||||
// DELETE请求
|
||||
func (c *Client) Delete(url, data string) (*ClientResponse, error) {
|
||||
return c.DoRequest("DELETE", url, []byte(data))
|
||||
func (c *Client) Delete(url string, data...string) (*ClientResponse, error) {
|
||||
return c.DoRequest("DELETE", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) Head(url, data string) (*ClientResponse, error) {
|
||||
return c.DoRequest("HEAD", url, []byte(data))
|
||||
func (c *Client) Head(url string, data...string) (*ClientResponse, error) {
|
||||
return c.DoRequest("HEAD", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) Patch(url, data string) (*ClientResponse, error) {
|
||||
return c.DoRequest("PATCH", url, []byte(data))
|
||||
func (c *Client) Patch(url string, data...string) (*ClientResponse, error) {
|
||||
return c.DoRequest("PATCH", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) Connect(url, data string) (*ClientResponse, error) {
|
||||
return c.DoRequest("CONNECT", url, []byte(data))
|
||||
func (c *Client) Connect(url string, data...string) (*ClientResponse, error) {
|
||||
return c.DoRequest("CONNECT", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) Options(url, data string) (*ClientResponse, error) {
|
||||
return c.DoRequest("OPTIONS", url, []byte(data))
|
||||
func (c *Client) Options(url string, data...string) (*ClientResponse, error) {
|
||||
return c.DoRequest("OPTIONS", url, data...)
|
||||
}
|
||||
|
||||
func (c *Client) Trace(url, data string) (*ClientResponse, error) {
|
||||
return c.DoRequest("TRACE", url, []byte(data))
|
||||
func (c *Client) Trace(url string, data...string) (*ClientResponse, error) {
|
||||
return c.DoRequest("TRACE", url, data...)
|
||||
}
|
||||
|
||||
// GET请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
@ -220,11 +224,7 @@ func (c *Client) TraceContent(url string, data...string) string {
|
||||
|
||||
// 请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
|
||||
func (c *Client) DoRequestContent(method string, url string, data...string) string {
|
||||
content := ""
|
||||
if len(data) > 0 {
|
||||
content = data[0]
|
||||
}
|
||||
response, err := c.DoRequest(method, url, []byte(content))
|
||||
response, err := c.DoRequest(method, url, data...)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
@ -233,14 +233,18 @@ func (c *Client) DoRequestContent(method string, url string, data...string) stri
|
||||
}
|
||||
|
||||
// 请求并返回response对象,该方法支持二进制提交数据
|
||||
func (c *Client) DoRequest(method, url string, data []byte) (*ClientResponse, error) {
|
||||
func (c *Client) DoRequest(method, url string, data...string) (*ClientResponse, error) {
|
||||
if strings.EqualFold("POST", method) {
|
||||
return c.Post(url, string(data))
|
||||
return c.Post(url, data...)
|
||||
}
|
||||
if len(c.prefix) > 0 {
|
||||
url = c.prefix + url
|
||||
}
|
||||
req, err := http.NewRequest(strings.ToUpper(method), url, bytes.NewReader(data))
|
||||
param := ""
|
||||
if len(data) > 0 {
|
||||
param = data[0]
|
||||
}
|
||||
req, err := http.NewRequest(strings.ToUpper(method), url, bytes.NewReader([]byte(param)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ type ClientResponse struct {
|
||||
http.Response
|
||||
}
|
||||
|
||||
// 获取返回的数据
|
||||
// 获取返回的数据(二进制).
|
||||
func (r *ClientResponse) ReadAll() []byte {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
@ -26,6 +26,11 @@ func (r *ClientResponse) ReadAll() []byte {
|
||||
return body
|
||||
}
|
||||
|
||||
// 获取返回的数据(字符串).
|
||||
func (r *ClientResponse) ReadAllString() string {
|
||||
return string(r.ReadAll())
|
||||
}
|
||||
|
||||
// 关闭返回的HTTP链接
|
||||
func (r *ClientResponse) Close() {
|
||||
r.Response.Close = true
|
||||
|
||||
@ -32,7 +32,6 @@ func newResponse(s *Server, w http.ResponseWriter) *Response {
|
||||
Server : s,
|
||||
ResponseWriter : ResponseWriter {
|
||||
ResponseWriter : w,
|
||||
Status : http.StatusOK,
|
||||
buffer : bytes.NewBuffer(nil),
|
||||
},
|
||||
}
|
||||
@ -137,9 +136,8 @@ func (r *Response) WriteStatus(status int, content...string) {
|
||||
if status != http.StatusOK {
|
||||
if f := r.request.Server.getStatusHandler(status, r.request); f != nil {
|
||||
f(r.request)
|
||||
// 如果是http.StatusOK那么表示回调函数内部没有设置header status,
|
||||
// 那么这里就可以设置status,防止多次设置(http: multiple response.WriteHeader calls)
|
||||
if r.Status == http.StatusOK {
|
||||
// 防止多次设置(http: multiple response.WriteHeader calls)
|
||||
if r.Status == 0 {
|
||||
r.WriteHeader(status)
|
||||
}
|
||||
return
|
||||
|
||||
@ -46,14 +46,28 @@ func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
request := newRequest(s, r, w)
|
||||
|
||||
defer func() {
|
||||
if request.LeaveTime == 0 {
|
||||
request.LeaveTime = gtime.Microsecond()
|
||||
// 设置请求完成时间
|
||||
request.LeaveTime = gtime.Microsecond()
|
||||
// 事件 - BeforeOutput
|
||||
if !request.IsExited() {
|
||||
s.callHookHandler(HOOK_BEFORE_OUTPUT, request)
|
||||
}
|
||||
// 输出Cookie
|
||||
request.Cookie.Output()
|
||||
// 输出缓冲区
|
||||
request.Response.OutputBuffer()
|
||||
// 事件 - AfterOutput
|
||||
if !request.IsExited() {
|
||||
s.callHookHandler(HOOK_AFTER_OUTPUT, request)
|
||||
}
|
||||
|
||||
// 事件 - BeforeClose
|
||||
s.callHookHandler(HOOK_BEFORE_CLOSE, request)
|
||||
// access log
|
||||
s.handleAccessLog(request)
|
||||
// error log使用recover进行判断
|
||||
if e := recover(); e != nil {
|
||||
request.Response.WriteStatus(http.StatusInternalServerError)
|
||||
s.handleErrorLog(e, request)
|
||||
}
|
||||
// 更新Session会话超时时间
|
||||
@ -125,22 +139,6 @@ func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
if !request.IsExited() {
|
||||
s.callHookHandler(HOOK_AFTER_SERVE, request)
|
||||
}
|
||||
|
||||
// 设置请求完成时间
|
||||
request.LeaveTime = gtime.Microsecond()
|
||||
|
||||
// 事件 - BeforeOutput
|
||||
if !request.IsExited() {
|
||||
s.callHookHandler(HOOK_BEFORE_OUTPUT, request)
|
||||
}
|
||||
// 输出Cookie
|
||||
request.Cookie.Output()
|
||||
// 输出缓冲区
|
||||
request.Response.OutputBuffer()
|
||||
// 事件 - AfterOutput
|
||||
if !request.IsExited() {
|
||||
s.callHookHandler(HOOK_AFTER_OUTPUT, request)
|
||||
}
|
||||
}
|
||||
|
||||
// 查找静态文件的绝对路径
|
||||
|
||||
@ -10,7 +10,6 @@ package ghttp
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// 处理服务错误信息,主要是panic,http请求的status由access log进行管理
|
||||
@ -34,8 +33,6 @@ func (s *Server) handleAccessLog(r *Request) {
|
||||
|
||||
// 处理服务错误信息,主要是panic,http请求的status由access log进行管理
|
||||
func (s *Server) handleErrorLog(error interface{}, r *Request) {
|
||||
r.Response.WriteStatus(http.StatusInternalServerError)
|
||||
|
||||
// 错误输出默认是开启的
|
||||
if !s.IsErrorLogEnabled() && gfile.MainPkgPath() == "" {
|
||||
return
|
||||
|
||||
@ -17,6 +17,7 @@ import (
|
||||
)
|
||||
|
||||
|
||||
// 基本路由功能测试
|
||||
func Test_Router_Basic(t *testing.T) {
|
||||
s := g.Server(gtime.Nanosecond())
|
||||
s.BindHandler("/:name", func(r *ghttp.Request){
|
||||
@ -53,3 +54,155 @@ func Test_Router_Basic(t *testing.T) {
|
||||
gtest.Assert(client.GetContent("/user/list/100.html"), "100")
|
||||
})
|
||||
}
|
||||
|
||||
// 测试HTTP Method注册.
|
||||
func Test_Router_Method(t *testing.T) {
|
||||
s := g.Server(gtime.Nanosecond())
|
||||
s.BindHandler("GET:/get", func(r *ghttp.Request){
|
||||
|
||||
})
|
||||
s.BindHandler("POST:/post", func(r *ghttp.Request){
|
||||
|
||||
})
|
||||
s.SetPort(8105)
|
||||
s.SetDumpRouteMap(false)
|
||||
go s.Run()
|
||||
defer func() {
|
||||
s.Shutdown()
|
||||
time.Sleep(time.Second)
|
||||
}()
|
||||
// 等待启动完成
|
||||
time.Sleep(time.Second)
|
||||
gtest.Case(t, func() {
|
||||
client := ghttp.NewClient()
|
||||
client.SetPrefix("http://127.0.0.1:8105")
|
||||
|
||||
resp1, err := client.Get("/get")
|
||||
defer resp1.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp1.StatusCode, 200)
|
||||
|
||||
resp2, err := client.Post("/get")
|
||||
defer resp2.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp2.StatusCode, 404)
|
||||
|
||||
resp3, err := client.Get("/post")
|
||||
defer resp3.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp3.StatusCode, 404)
|
||||
|
||||
resp4, err := client.Post("/post")
|
||||
defer resp4.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp4.StatusCode, 200)
|
||||
})
|
||||
}
|
||||
|
||||
// 测试状态返回.
|
||||
func Test_Router_Status(t *testing.T) {
|
||||
s := g.Server(gtime.Nanosecond())
|
||||
s.BindHandler("/200", func(r *ghttp.Request){
|
||||
r.Response.WriteStatus(200)
|
||||
})
|
||||
s.BindHandler("/300", func(r *ghttp.Request){
|
||||
r.Response.WriteStatus(300)
|
||||
})
|
||||
s.BindHandler("/400", func(r *ghttp.Request){
|
||||
r.Response.WriteStatus(400)
|
||||
})
|
||||
s.BindHandler("/500", func(r *ghttp.Request){
|
||||
r.Response.WriteStatus(500)
|
||||
})
|
||||
s.SetPort(8110)
|
||||
s.SetDumpRouteMap(false)
|
||||
go s.Run()
|
||||
defer func() {
|
||||
s.Shutdown()
|
||||
time.Sleep(time.Second)
|
||||
}()
|
||||
// 等待启动完成
|
||||
time.Sleep(time.Second)
|
||||
gtest.Case(t, func() {
|
||||
client := ghttp.NewClient()
|
||||
client.SetPrefix("http://127.0.0.1:8110")
|
||||
|
||||
resp1, err := client.Get("/200")
|
||||
defer resp1.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp1.StatusCode, 200)
|
||||
|
||||
resp2, err := client.Get("/300")
|
||||
defer resp2.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp2.StatusCode, 300)
|
||||
|
||||
resp3, err := client.Get("/400")
|
||||
defer resp3.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp3.StatusCode, 400)
|
||||
|
||||
resp4, err := client.Get("/500")
|
||||
defer resp4.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp4.StatusCode, 500)
|
||||
})
|
||||
}
|
||||
|
||||
// 自定义状态码处理.
|
||||
func Test_Router_CustomStatusHandler(t *testing.T) {
|
||||
s := g.Server(gtime.Nanosecond())
|
||||
s.BindHandler("/", func(r *ghttp.Request){
|
||||
r.Response.Write("hello")
|
||||
})
|
||||
s.BindStatusHandler(404, func(r *ghttp.Request){
|
||||
r.Response.Write("404 page")
|
||||
})
|
||||
s.SetPort(8120)
|
||||
s.SetDumpRouteMap(false)
|
||||
go s.Run()
|
||||
defer func() {
|
||||
s.Shutdown()
|
||||
time.Sleep(time.Second)
|
||||
}()
|
||||
// 等待启动完成
|
||||
time.Sleep(time.Second)
|
||||
gtest.Case(t, func() {
|
||||
client := ghttp.NewClient()
|
||||
client.SetPrefix("http://127.0.0.1:8120")
|
||||
|
||||
gtest.Assert(client.GetContent("/"), "hello")
|
||||
resp, err := client.Get("/ThisDoesNotExist")
|
||||
defer resp.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp.StatusCode, 404)
|
||||
gtest.Assert(resp.ReadAllString(), "404 page")
|
||||
})
|
||||
}
|
||||
|
||||
// 测试不存在的路由.
|
||||
func Test_Router_404(t *testing.T) {
|
||||
s := g.Server(gtime.Nanosecond())
|
||||
s.BindHandler("/", func(r *ghttp.Request){
|
||||
r.Response.Write("hello")
|
||||
})
|
||||
s.SetPort(8130)
|
||||
s.SetDumpRouteMap(false)
|
||||
go s.Run()
|
||||
defer func() {
|
||||
s.Shutdown()
|
||||
time.Sleep(time.Second)
|
||||
}()
|
||||
// 等待启动完成
|
||||
time.Sleep(time.Second)
|
||||
gtest.Case(t, func() {
|
||||
client := ghttp.NewClient()
|
||||
client.SetPrefix("http://127.0.0.1:8130")
|
||||
|
||||
gtest.Assert(client.GetContent("/"), "hello")
|
||||
resp, err := client.Get("/ThisDoesNotExist")
|
||||
defer resp.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp.StatusCode, 404)
|
||||
})
|
||||
}
|
||||
@ -82,6 +82,11 @@ func Test_Router_Group1(t *testing.T) {
|
||||
gtest.Assert(client.GetContent ("/api/obj/show"), "Object Show")
|
||||
gtest.Assert(client.DeleteContent("/api/obj/rest"), "Object REST Delete")
|
||||
|
||||
// 测试404
|
||||
resp, err := client.Get("/ThisDoesNotExist")
|
||||
defer resp.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp.StatusCode, 404)
|
||||
})
|
||||
}
|
||||
|
||||
@ -122,5 +127,11 @@ func Test_Router_Group2(t *testing.T) {
|
||||
gtest.Assert(client.GetContent ("/api/obj/my-show"), "Object Show")
|
||||
gtest.Assert(client.GetContent ("/api/obj/show"), "Object Show")
|
||||
gtest.Assert(client.DeleteContent("/api/obj/rest"), "Object REST Delete")
|
||||
|
||||
// 测试404
|
||||
resp, err := client.Get("/ThisDoesNotExist")
|
||||
defer resp.Close()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(resp.StatusCode, 404)
|
||||
})
|
||||
}
|
||||
|
||||
@ -88,25 +88,6 @@ func UcWords(str string) string {
|
||||
return strings.Title(str)
|
||||
}
|
||||
|
||||
// Traverse the array to find the string index position, if not exist, return-1.
|
||||
//
|
||||
// 遍历数组查找字符串索引位置,如果不存在则返回-1,使用完整遍历查找.
|
||||
func SearchArray (a []string, s string) int {
|
||||
for i, v := range a {
|
||||
if s == v {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// InArray tests whether the given string s is in string array a.
|
||||
//
|
||||
// 判断字符串是否在数组中
|
||||
func InArray (a []string, s string) bool {
|
||||
return SearchArray(a, s) != -1
|
||||
}
|
||||
|
||||
// IsLetterLower tests whether the given byte b is in lower case.
|
||||
//
|
||||
// 判断给定字符是否小写
|
||||
@ -490,15 +471,7 @@ func Explode(delimiter, str string) []string {
|
||||
//
|
||||
// 用glue将字符串数组pieces连接为一个字符串。
|
||||
func Implode(glue string, pieces []string) string {
|
||||
var buf bytes.Buffer
|
||||
l := len(pieces)
|
||||
for _, str := range pieces {
|
||||
buf.WriteString(str)
|
||||
if l--; l > 0 {
|
||||
buf.WriteString(glue)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
return strings.Join(pieces, glue)
|
||||
}
|
||||
|
||||
// Generate a single-byte string from a number.
|
||||
|
||||
@ -68,26 +68,6 @@ func Test_UcWords(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SearchArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
array := []string{"a", "b", "c"}
|
||||
gtest.Assert(gstr.SearchArray(array, "a"), 0)
|
||||
gtest.Assert(gstr.SearchArray(array, "b"), 1)
|
||||
gtest.Assert(gstr.SearchArray(array, "c"), 2)
|
||||
gtest.Assert(gstr.SearchArray(array, "d"), -1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_InArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
array := []string{"a", "b", "c"}
|
||||
gtest.Assert(gstr.InArray(array, "a"), true)
|
||||
gtest.Assert(gstr.InArray(array, "b"), true)
|
||||
gtest.Assert(gstr.InArray(array, "c"), true)
|
||||
gtest.Assert(gstr.InArray(array, "d"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IsLetterLower(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gstr.IsLetterLower('a'), true)
|
||||
|
||||
@ -2,11 +2,13 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f, e := gfile.Open("/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/third")
|
||||
fmt.Println(e)
|
||||
fmt.Println(f)
|
||||
s := "abc我是中国人é"
|
||||
fmt.Println(len(s))
|
||||
|
||||
for i := 0; i < len(s); i++ {
|
||||
fmt.Println(s[i])
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.5.0"
|
||||
const VERSION = "v1.5.3"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user