add GetRemoteIp for ghttp.Request; add *Var feature for ghttp.Client

This commit is contained in:
Jack 2020-08-11 15:23:42 +08:00
parent 7b599d1882
commit a95093222c
9 changed files with 547 additions and 7 deletions

View File

@ -6,6 +6,8 @@
package ghttp
import "github.com/gogf/gf/container/gvar"
// Get is a convenience method for sending GET request.
// NOTE that remembers CLOSING the response object when it'll never be used.
func Get(url string, data ...interface{}) (*ClientResponse, error) {
@ -185,3 +187,69 @@ func TraceBytes(url string, data ...interface{}) []byte {
func RequestBytes(method string, url string, data ...interface{}) []byte {
return NewClient().RequestBytes(method, url, data...)
}
// GetVar sends a GET request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, et
func GetVar(url string, data ...interface{}) *gvar.Var {
return RequestVar("GET", url, data...)
}
// PutVar sends a PUT request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, et
func PutVar(url string, data ...interface{}) *gvar.Var {
return RequestVar("PUT", url, data...)
}
// PostVar sends a POST request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, et
func PostVar(url string, data ...interface{}) *gvar.Var {
return RequestVar("POST", url, data...)
}
// DeleteVar sends a DELETE request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, et
func DeleteVar(url string, data ...interface{}) *gvar.Var {
return RequestVar("DELETE", url, data...)
}
// HeadVar sends a HEAD request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, et
func HeadVar(url string, data ...interface{}) *gvar.Var {
return RequestVar("HEAD", url, data...)
}
// PatchVar sends a PATCH request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, et
func PatchVar(url string, data ...interface{}) *gvar.Var {
return RequestVar("PATCH", url, data...)
}
// ConnectVar sends a CONNECT request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, et
func ConnectVar(url string, data ...interface{}) *gvar.Var {
return RequestVar("CONNECT", url, data...)
}
// OptionsVar sends a OPTIONS request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, et
func OptionsVar(url string, data ...interface{}) *gvar.Var {
return RequestVar("OPTIONS", url, data...)
}
// TraceVar sends a TRACE request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, et
func TraceVar(url string, data ...interface{}) *gvar.Var {
return RequestVar("TRACE", url, data...)
}
// RequestVar sends request using given HTTP method and data, retrieves converts the result
// to specified pointer. It reads and closes the response object internally automatically.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, et
func RequestVar(method string, url string, data ...interface{}) *gvar.Var {
response, err := DoRequest(method, url, data...)
if err != nil {
return gvar.New(nil)
}
defer response.Close()
return gvar.New(response.ReadAll())
}

View File

@ -0,0 +1,77 @@
// 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 (
"github.com/gogf/gf/container/gvar"
)
// GetVar sends a GET request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
func (c *Client) GetVar(url string, data ...interface{}) *gvar.Var {
return c.RequestVar("GET", url, data...)
}
// PutVar sends a PUT request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
func (c *Client) PutVar(url string, data ...interface{}) *gvar.Var {
return c.RequestVar("PUT", url, data...)
}
// PostVar sends a POST request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
func (c *Client) PostVar(url string, data ...interface{}) *gvar.Var {
return c.RequestVar("POST", url, data...)
}
// DeleteVar sends a DELETE request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
func (c *Client) DeleteVar(url string, data ...interface{}) *gvar.Var {
return c.RequestVar("DELETE", url, data...)
}
// HeadVar sends a HEAD request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
func (c *Client) HeadVar(url string, data ...interface{}) *gvar.Var {
return c.RequestVar("HEAD", url, data...)
}
// PatchVar sends a PATCH request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
func (c *Client) PatchVar(url string, data ...interface{}) *gvar.Var {
return c.RequestVar("PATCH", url, data...)
}
// ConnectVar sends a CONNECT request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
func (c *Client) ConnectVar(url string, data ...interface{}) *gvar.Var {
return c.RequestVar("CONNECT", url, data...)
}
// OptionsVar sends a OPTIONS request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
func (c *Client) OptionsVar(url string, data ...interface{}) *gvar.Var {
return c.RequestVar("OPTIONS", url, data...)
}
// TraceVar sends a TRACE request, retrieves and converts the result content to specified pointer.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
func (c *Client) TraceVar(url string, data ...interface{}) *gvar.Var {
return c.RequestVar("TRACE", url, data...)
}
// RequestVar sends request using given HTTP method and data, retrieves converts the result
// to specified pointer. It reads and closes the response object internally automatically.
// The parameter <pointer> can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
func (c *Client) RequestVar(method string, url string, data ...interface{}) *gvar.Var {
response, err := c.DoRequest(method, url, data...)
if err != nil {
return gvar.New(nil)
}
defer response.Close()
return gvar.New(response.ReadAll())
}

View File

@ -155,6 +155,7 @@ func (r *Request) IsAjaxRequest() bool {
}
// GetClientIp returns the client ip of this request without port.
// Note that this ip address might be modified by client header.
func (r *Request) GetClientIp() string {
if len(r.clientIp) == 0 {
realIps := r.Header.Get("X-Forwarded-For")
@ -178,17 +179,21 @@ func (r *Request) GetClientIp() string {
r.clientIp = r.Header.Get("X-Real-IP")
}
if r.clientIp == "" || strings.EqualFold("unknown", realIps) {
array, _ := gregex.MatchString(`(.+):(\d+)`, r.RemoteAddr)
if len(array) > 1 {
r.clientIp = array[1]
} else {
r.clientIp = r.RemoteAddr
}
r.clientIp = r.GetRemoteIp()
}
}
return r.clientIp
}
// GetRemoteIp returns the ip from RemoteAddr.
func (r *Request) GetRemoteIp() string {
array, _ := gregex.MatchString(`(.+):(\d+)`, r.RemoteAddr)
if len(array) > 1 {
return array[1]
}
return r.RemoteAddr
}
// GetUrl returns current URL of this request.
func (r *Request) GetUrl() string {
scheme := "http"

View File

@ -17,7 +17,7 @@ var (
func init() {
genv.Set("UNDER_TEST", "1")
for i := 8000; i <= 9000; i++ {
for i := 50000; i <= 51000; i++ {
ports.Append(i)
}
}

View File

@ -0,0 +1,41 @@
// Copyright 2020 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.
// static service testing.
package ghttp_test
import (
"fmt"
"testing"
"time"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
"github.com/gogf/gf/test/gtest"
)
func TestRequest_GetRemoteIp(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
p, _ := ports.PopRand()
s := g.Server(p)
s.BindHandler("/", func(r *ghttp.Request) {
r.Response.Write(r.GetRemoteIp())
})
s.SetDumpRouterMap(false)
s.SetPort(p)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
client := ghttp.NewClient()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
t.Assert(client.GetContent("/"), "127.0.0.1")
})
}

View File

@ -0,0 +1,86 @@
// Copyright 2020 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_test
import (
"fmt"
"github.com/gogf/gf/frame/g"
)
func ExampleClient_Header() {
var (
url = "http://127.0.0.1:8999/header"
header = g.MapStrStr{
"Span-Id": "0.1",
"Trace-Id": "123456789",
}
)
content := g.Client().Header(header).PostContent(url, g.Map{
"id": 10000,
"name": "john",
})
fmt.Println(content)
// Output:
// Span-Id: 0.1, Trace-Id: 123456789
}
func ExampleClient_HeaderRaw() {
var (
url = "http://127.0.0.1:8999/header"
headerRaw = `
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3950.0 Safari/537.36
Span-Id: 0.1
Trace-Id: 123456789
`
)
content := g.Client().HeaderRaw(headerRaw).PostContent(url, g.Map{
"id": 10000,
"name": "john",
})
fmt.Println(content)
// Output:
// Span-Id: 0.1, Trace-Id: 123456789
}
func ExampleClient_Cookie() {
var (
url = "http://127.0.0.1:8999/cookie"
cookie = g.MapStrStr{
"SessionId": "123",
}
)
content := g.Client().Cookie(cookie).PostContent(url, g.Map{
"id": 10000,
"name": "john",
})
fmt.Println(content)
// Output:
// SessionId: 123
}
func ExampleClient_ContentJson() {
var (
url = "http://127.0.0.1:8999/json"
jsonStr = `{"id":10000,"name":"john"}`
jsonMap = g.Map{
"id": 10000,
"name": "john",
}
)
// Post using JSON string.
fmt.Println(g.Client().ContentJson().PostContent(url, jsonStr))
// Post using JSON map.
fmt.Println(g.Client().ContentJson().PostContent(url, jsonMap))
// Output:
// Content-Type: application/json, id: 10000
// Content-Type: application/json, id: 10000
}

View File

@ -0,0 +1,89 @@
// Copyright 2020 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_test
import (
"fmt"
"github.com/gogf/gf/frame/g"
)
func ExampleClient_Get() {
url := "http://127.0.0.1:8999"
// Send with string parameter along with URL.
r1, err := g.Client().Get(url + "?id=10000&name=john")
if err != nil {
panic(err)
}
defer r1.Close()
fmt.Println(r1.ReadAllString())
// Send with string parameter in request body.
r2, err := g.Client().Get(url, "id=10000&name=john")
if err != nil {
panic(err)
}
defer r2.Close()
fmt.Println(r2.ReadAllString())
// Send with map parameter.
r3, err := g.Client().Get(url, g.Map{
"id": 10000,
"name": "john",
})
if err != nil {
panic(err)
}
defer r3.Close()
fmt.Println(r3.ReadAllString())
// Output:
// GET: query: 10000, john
// GET: query: 10000, john
// GET: query: 10000, john
}
func ExampleClient_GetBytes() {
url := "http://127.0.0.1:8999"
fmt.Println(string(g.Client().GetBytes(url, g.Map{
"id": 10000,
"name": "john",
})))
// Output:
// GET: query: 10000, john
}
func ExampleClient_GetContent() {
url := "http://127.0.0.1:8999"
fmt.Println(g.Client().GetContent(url, g.Map{
"id": 10000,
"name": "john",
}))
// Output:
// GET: query: 10000, john
}
func ExampleClient_GetVar() {
type User struct {
Id int
Name string
}
var (
user *User
url = "http://127.0.0.1:8999/var/json"
)
err := g.Client().GetVar(url).Scan(&user)
if err != nil {
panic(err)
}
fmt.Println(user)
// Output:
// &{1 john}
}

View File

@ -0,0 +1,95 @@
// Copyright 2020 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_test
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
"time"
)
func init() {
p := 8999
s := g.Server(p)
// HTTP method handlers.
s.Group("/", func(group *ghttp.RouterGroup) {
group.GET("/", func(r *ghttp.Request) {
r.Response.Writef(
"GET: query: %d, %s",
r.GetQueryInt("id"),
r.GetQueryString("name"),
)
})
group.PUT("/", func(r *ghttp.Request) {
r.Response.Writef(
"PUT: form: %d, %s",
r.GetFormInt("id"),
r.GetFormString("name"),
)
})
group.POST("/", func(r *ghttp.Request) {
r.Response.Writef(
"POST: form: %d, %s",
r.GetFormInt("id"),
r.GetFormString("name"),
)
})
group.DELETE("/", func(r *ghttp.Request) {
r.Response.Writef(
"DELETE: form: %d, %s",
r.GetFormInt("id"),
r.GetFormString("name"),
)
})
group.HEAD("/", func(r *ghttp.Request) {
r.Response.Write("head")
})
group.OPTIONS("/", func(r *ghttp.Request) {
r.Response.Write("options")
})
})
// Client chaining operations handlers.
s.Group("/", func(group *ghttp.RouterGroup) {
group.ALL("/header", func(r *ghttp.Request) {
r.Response.Writef(
"Span-Id: %s, Trace-Id: %s",
r.Header.Get("Span-Id"),
r.Header.Get("Trace-Id"),
)
})
group.ALL("/cookie", func(r *ghttp.Request) {
r.Response.Writef(
"SessionId: %s",
r.Cookie.Get("SessionId"),
)
})
group.ALL("/json", func(r *ghttp.Request) {
r.Response.Writef(
"Content-Type: %s, id: %d",
r.Header.Get("Content-Type"),
r.GetInt("id"),
)
})
})
// Other testing handlers.
s.Group("/var", func(group *ghttp.RouterGroup) {
group.ALL("/json", func(r *ghttp.Request) {
r.Response.Write(`{"id":1,"name":"john"}`)
})
group.ALL("/jsons", func(r *ghttp.Request) {
r.Response.Write(`[{"id":1,"name":"john"}, {"id":2,"name":"smith"}]`)
})
})
s.SetAccessLogEnabled(false)
s.SetDumpRouterMap(false)
s.SetPort(p)
err := s.Start()
if err != nil {
panic(err)
}
time.Sleep(time.Millisecond * 500)
}

View File

@ -0,0 +1,79 @@
// Copyright 2020 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_test
import (
"fmt"
"github.com/gogf/gf/frame/g"
)
func ExampleClient_Post() {
url := "http://127.0.0.1:8999"
// Send with string parameter in request body.
r1, err := g.Client().Post(url, "id=10000&name=john")
if err != nil {
panic(err)
}
defer r1.Close()
fmt.Println(r1.ReadAllString())
// Send with map parameter.
r2, err := g.Client().Post(url, g.Map{
"id": 10000,
"name": "john",
})
if err != nil {
panic(err)
}
defer r2.Close()
fmt.Println(r2.ReadAllString())
// Output:
// POST: form: 10000, john
// POST: form: 10000, john
}
func ExampleClient_PostBytes() {
url := "http://127.0.0.1:8999"
fmt.Println(string(g.Client().PostBytes(url, g.Map{
"id": 10000,
"name": "john",
})))
// Output:
// POST: form: 10000, john
}
func ExampleClient_PostContent() {
url := "http://127.0.0.1:8999"
fmt.Println(g.Client().PostContent(url, g.Map{
"id": 10000,
"name": "john",
}))
// Output:
// POST: form: 10000, john
}
func ExampleClient_PostVar() {
type User struct {
Id int
Name string
}
var (
users []User
url = "http://127.0.0.1:8999/var/jsons"
)
err := g.Client().PostVar(url).Scan(&users)
if err != nil {
panic(err)
}
fmt.Println(users)
// Output:
// [{1 john} {2 smith}]
}