improve ghttp.Client

This commit is contained in:
John 2019-12-01 14:07:36 +08:00
parent 8bbeb186c2
commit 2a2cfc289c
15 changed files with 335 additions and 225 deletions

View File

@ -0,0 +1,9 @@
package main
import (
"github.com/gogf/gf/net/ghttp"
)
func main() {
ghttp.PostContent("http://127.0.0.1:8199/", "array[]=1&array[]=2")
}

View File

@ -8,7 +8,7 @@ import (
func main() {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
g.Dump(r.GetPostMap())
g.Dump(r.GetForm("array"))
r.Response.WriteTpl("form.html")
})
s.SetPort(8199)

View File

@ -4,99 +4,136 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// HTTP客户端请求.
package ghttp
import (
"crypto/tls"
"net/http"
"strings"
"time"
"github.com/gogf/gf/text/gregex"
)
// 是否模拟浏览器模式(自动保存提交COOKIE)
func (c *Client) SetBrowserMode(enabled bool) {
c.browserMode = enabled
// Client is the HTTP client for HTTP request management.
type Client struct {
http.Client // Underlying HTTP Client.
header map[string]string // Custom header map.
cookies map[string]string // Custom cookie map.
prefix string // Prefix for request.
authUser string // HTTP basic authentication: user.
authPass string // HTTP basic authentication: pass.
browserMode bool // Whether auto saving and sending cookie content.
retryCount int // Retry count when request fails.
retryInterval int // Retry interval when request fails.
}
// 设置HTTP Header
func (c *Client) SetHeader(key, value string) {
c.header[key] = value
}
func (c *Client) SetHeaderMap(m map[string]string) {
for k, v := range m {
c.header[k] = v
// NewClient creates and returns a new HTTP client object.
func NewClient() *Client {
return &Client{
Client: http.Client{
Transport: &http.Transport{
// No validation for https certification of the server.
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
DisableKeepAlives: true,
},
},
header: make(map[string]string),
cookies: make(map[string]string),
}
}
// 通过字符串设置HTTP Header
func (c *Client) SetHeaderRaw(header string) {
// Clone clones current client and returns a new one.
func (c *Client) Clone() *Client {
newClient := NewClient()
*newClient = *c
newClient.header = make(map[string]string)
newClient.cookies = make(map[string]string)
for k, v := range c.header {
newClient.header[k] = v
}
for k, v := range c.cookies {
newClient.cookies[k] = v
}
return newClient
}
// SetBrowserMode enables browser mode of the client.
// When browser mode is enabled, it automatically saves and sends cookie content
// from and to server.
func (c *Client) SetBrowserMode(enabled bool) *Client {
c.browserMode = enabled
return c
}
// SetHeader sets a custom HTTP header pair for the client.
func (c *Client) SetHeader(key, value string) *Client {
c.header[key] = value
return c
}
// SetHeaderMap sets custom HTTP headers with map.
func (c *Client) SetHeaderMap(m map[string]string) *Client {
for k, v := range m {
c.header[k] = v
}
return c
}
// SetContentType sets HTTP content type for the client.
func (c *Client) SetContentType(contentType string) *Client {
c.header["Content-Type"] = contentType
return c
}
// SetHeaderRaw sets custom HTTP header using raw string.
func (c *Client) SetHeaderRaw(header string) *Client {
for _, line := range strings.Split(strings.TrimSpace(header), "\n") {
array, _ := gregex.MatchString(`^([\w\-]+):\s*(.+)`, line)
if len(array) >= 3 {
c.header[array[1]] = array[2]
}
}
return c
}
// 设置COOKIE
func (c *Client) SetCookie(key, value string) {
// SetCookie sets a cookie pair for the client.
func (c *Client) SetCookie(key, value string) *Client {
c.cookies[key] = value
return c
}
// 使用Map设置COOKIE
func (c *Client) SetCookieMap(m map[string]string) {
// SetCookieMap sets cookie items with map.
func (c *Client) SetCookieMap(m map[string]string) *Client {
for k, v := range m {
c.cookies[k] = v
}
return c
}
// 设置请求的URL前缀
func (c *Client) SetPrefix(prefix string) {
// SetPrefix sets the request server URL prefix.
func (c *Client) SetPrefix(prefix string) *Client {
c.prefix = prefix
}
// 设置请求过期时间
func (c *Client) SetTimeOut(t time.Duration) {
c.Timeout = t
}
// 设置HTTP访问账号密码
func (c *Client) SetBasicAuth(user, pass string) {
c.authUser = user
c.authPass = pass
}
// 设置失败重试次数及间隔,失败仅针对网络请求失败情况。
// 重试间隔时间单位为秒。
func (c *Client) SetRetry(retryCount int, retryInterval int) {
c.retryCount = retryCount
c.retryInterval = retryInterval
}
// 链式操作, See SetBrowserMode
func (c *Client) BrowserMode(enabled bool) *Client {
c.browserMode = enabled
return c
}
// 链式操作, See SetTimeOut
func (c *Client) TimeOut(t time.Duration) *Client {
// SetTimeOut sets the request timeout for the client.
func (c *Client) SetTimeOut(t time.Duration) *Client {
c.Timeout = t
return c
}
// 链式操作, See SetBasicAuth
func (c *Client) BasicAuth(user, pass string) *Client {
// SetBasicAuth sets HTTP basic authentication information for the client.
func (c *Client) SetBasicAuth(user, pass string) *Client {
c.authUser = user
c.authPass = pass
return c
}
// 链式操作, See SetRetry
func (c *Client) Retry(retryCount int, retryInterval int) *Client {
// SetRetry sets retry count and interval.
func (c *Client) SetRetry(retryCount int, retryInterval int) *Client {
c.retryCount = retryCount
c.retryInterval = retryInterval
return c

View File

@ -8,7 +8,6 @@ package ghttp
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
@ -22,51 +21,6 @@ import (
"github.com/gogf/gf/os/gfile"
)
// Client is the HTTP client for HTTP request management.
type Client struct {
http.Client // Underlying HTTP Client.
header map[string]string // Custom header map.
cookies map[string]string // Custom cookie map.
prefix string // Prefix for request.
authUser string // HTTP basic authentication: user.
authPass string // HTTP basic authentication: pass.
browserMode bool // Whether auto saving and sending cookie content.
retryCount int // Retry count when request fails.
retryInterval int // Retry interval when request fails.
}
// NewClient creates and returns a new HTTP client object.
func NewClient() *Client {
return &Client{
Client: http.Client{
Transport: &http.Transport{
// No validation for https certification of the server.
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
DisableKeepAlives: true,
},
},
header: make(map[string]string),
cookies: make(map[string]string),
}
}
// Clone clones current client and returns a new one.
func (c *Client) Clone() *Client {
newClient := NewClient()
*newClient = *c
newClient.header = make(map[string]string)
newClient.cookies = make(map[string]string)
for k, v := range c.header {
newClient.header[k] = v
}
for k, v := range c.cookies {
newClient.cookies[k] = v
}
return newClient
}
// Get send GET request and returns the response object.
// Note that the response object MUST be closed if it'll be never used.
func (c *Client) Get(url string) (*ClientResponse, error) {
@ -259,6 +213,11 @@ func (c *Client) DoRequest(method, url string, data ...interface{}) (*ClientResp
req.Header.Set(k, v)
}
}
// Automatically set default content type to "application/x-www-form-urlencoded"
// if there' no content type set.
if _, ok := c.header["Content-Type"]; !ok {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
// Custom cookie.
if len(c.cookies) > 0 {
headerCookie := ""

View File

@ -36,13 +36,13 @@ type Request struct {
parsedQuery bool // A bool marking whether the GET parameters parsed.
parsedBody bool // A bool marking whether the request body parsed.
parsedForm bool // A bool marking whether request Form parsed for HTTP method PUT, POST, PATCH.
paramsMap map[string]interface{} // Custom parameters.
routerMap map[string]interface{} // Router parameters map, which might be nil if there're no router parameters.
queryMap map[string]interface{} // Query parameters map, which is nil if there's no query string.
formMap map[string]interface{} // Form parameters map, which is nil if there's no form.
formMap map[string]interface{} // Form parameters map, which is nil if there's no form data from client.
bodyMap map[string]interface{} // Body parameters map, which might be nil if there're no body content.
error error // Current executing error of the request.
exit bool // A bool marking whether current request is exited.
params map[string]interface{} // Custom parameters.
parsedHost string // The parsed host name for current host used by GetHost function.
clientIp string // The parsed client ip for current host used by GetClientIp function.
bodyContent []byte // Request body content.

View File

@ -209,6 +209,11 @@ func (r *Request) ParseForm() {
if r.formMap, err = gstr.Parse(params); err != nil {
panic(err)
}
} else {
r.ParseBody()
if len(r.bodyMap) > 0 {
r.formMap = r.bodyMap
}
}
}
}

View File

@ -10,18 +10,18 @@ import "github.com/gogf/gf/container/gvar"
// SetParam sets custom parameter with key-value pair.
func (r *Request) SetParam(key string, value interface{}) {
if r.params == nil {
r.params = make(map[string]interface{})
if r.paramsMap == nil {
r.paramsMap = make(map[string]interface{})
}
r.params[key] = value
r.paramsMap[key] = value
}
// GetParam returns custom parameter with given name <key>.
// It returns <def> if <key> does not exist.
// It returns nil if <def> is not passed.
func (r *Request) GetParam(key string, def ...interface{}) interface{} {
if r.params != nil {
return r.params[key]
if r.paramsMap != nil {
return r.paramsMap[key]
}
if len(def) > 0 {
return def[0]

View File

@ -106,11 +106,11 @@ func (r *Request) GetFormInterfaces(key string, def ...interface{}) []interface{
// the associated values are the default values if the client does not pass.
func (r *Request) GetFormMap(kvMap ...map[string]interface{}) map[string]interface{} {
r.ParseForm()
if len(kvMap) > 0 {
if len(kvMap) > 0 && kvMap[0] != nil {
if len(r.formMap) == 0 {
return kvMap[0]
}
m := make(map[string]interface{})
m := make(map[string]interface{}, len(kvMap[0]))
for k, defValue := range kvMap[0] {
if postValue, ok := r.formMap[k]; ok {
m[k] = postValue

View File

@ -15,16 +15,19 @@ import (
// GetPost retrieves and returns parameter <key> from form and body.
// It returns <def> if <key> does not exist in neither form nor body.
// It returns nil if <def> is not passed.
//
// Note that if there're multiple parameters with the same name, the parameters are retrieved and overwrote
// in order of priority: form < body.
func (r *Request) GetPost(key string, def ...interface{}) interface{} {
r.ParseForm()
r.ParseBody()
if len(r.formMap) > 0 {
if v, ok := r.formMap[key]; ok {
if len(r.bodyMap) > 0 {
if v, ok := r.bodyMap[key]; ok {
return v
}
}
if len(r.bodyMap) > 0 {
if v, ok := r.bodyMap[key]; ok {
if len(r.formMap) > 0 {
if v, ok := r.formMap[key]; ok {
return v
}
}
@ -101,38 +104,39 @@ func (r *Request) GetPostInterfaces(key string, def ...interface{}) []interface{
// GetPostMap retrieves and returns all parameters in the form and body passed from client
// as map. The parameter <kvMap> specifies the keys retrieving from client parameters,
// the associated values are the default values if the client does not pass.
//
// Note that if there're multiple parameters with the same name, the parameters are retrieved and overwrote
// in order of priority: form < body.
func (r *Request) GetPostMap(kvMap ...map[string]interface{}) map[string]interface{} {
r.ParseForm()
r.ParseBody()
var ok, filter bool
if len(kvMap) > 0 && kvMap[0] != nil {
filter = true
}
m := make(map[string]interface{}, len(r.formMap)+len(r.bodyMap))
if len(kvMap) > 0 {
if len(r.formMap) == 0 && len(r.bodyMap) == 0 {
return kvMap[0]
}
if len(r.formMap) > 0 {
for k, v := range kvMap[0] {
if postValue, ok := r.formMap[k]; ok {
m[k] = postValue
} else {
m[k] = v
}
for k, v := range r.formMap {
if filter {
if _, ok = kvMap[0][k]; !ok {
continue
}
}
if len(r.bodyMap) > 0 {
for k, v := range kvMap[0] {
if postValue, ok := r.bodyMap[k]; ok {
m[k] = postValue
} else {
m[k] = v
}
m[k] = v
}
for k, v := range r.bodyMap {
if filter {
if _, ok = kvMap[0][k]; !ok {
continue
}
}
} else {
for k, v := range r.formMap {
m[k] = v
}
for k, v := range r.bodyMap {
m[k] = v
m[k] = v
}
// Check none exist parameters and assign it with default value.
if filter {
for k, v := range kvMap[0] {
if _, ok = m[k]; !ok {
m[k] = v
}
}
}
return m

View File

@ -25,16 +25,19 @@ func (r *Request) SetQuery(key string, value interface{}) {
// GetQuery retrieves and returns parameter with given name <key> from query string
// and request body. It returns <def> if <key> does not exist in the query. It returns nil
// if <def> is not passed.
//
// Note that if there're multiple parameters with the same name, the parameters are retrieved and overwrote
// in order of priority: query < body.
func (r *Request) GetQuery(key string, def ...interface{}) interface{} {
r.ParseQuery()
r.ParseBody()
if len(r.queryMap) > 0 {
if v, ok := r.queryMap[key]; ok {
if len(r.bodyMap) > 0 {
if v, ok := r.bodyMap[key]; ok {
return v
}
}
if len(r.bodyMap) > 0 {
if v, ok := r.bodyMap[key]; ok {
if len(r.queryMap) > 0 {
if v, ok := r.queryMap[key]; ok {
return v
}
}
@ -111,14 +114,18 @@ func (r *Request) GetQueryInterfaces(key string, def ...interface{}) []interface
// GetQueryMap retrieves and returns all parameters passed from client using HTTP GET method
// as map. The parameter <kvMap> specifies the keys retrieving from client parameters,
// the associated values are the default values if the client does not pass.
//
// Note that if there're multiple parameters with the same name, the parameters are retrieved and overwrote
// in order of priority: query < body.
func (r *Request) GetQueryMap(kvMap ...map[string]interface{}) map[string]interface{} {
r.ParseQuery()
r.ParseBody()
m := make(map[string]interface{}, len(r.queryMap)+len(r.bodyMap))
if len(kvMap) > 0 {
var m map[string]interface{}
if len(kvMap) > 0 && kvMap[0] != nil {
if len(r.queryMap) == 0 && len(r.bodyMap) == 0 {
return kvMap[0]
}
m = make(map[string]interface{}, len(kvMap[0]))
if len(r.queryMap) > 0 {
for k, v := range kvMap[0] {
if postValue, ok := r.queryMap[k]; ok {
@ -138,6 +145,7 @@ func (r *Request) GetQueryMap(kvMap ...map[string]interface{}) map[string]interf
}
}
} else {
m = make(map[string]interface{}, len(r.queryMap)+len(r.bodyMap))
for k, v := range r.queryMap {
m[k] = v
}

View File

@ -12,32 +12,38 @@ import (
"github.com/gogf/gf/util/gconv"
)
// GetRequestVar retrieves and returns the parameter named <key> passed from client as interface{},
// GetRequest retrieves and returns the parameter named <key> passed from client as interface{},
// no matter what HTTP method the client is using. The parameter <def> specifies the default value
// if the <key> does not exist.
//
// Note that the parameter is retrieved in order of: router->get/body->post/body->param.
// GetRequest is one of the most commonly used functions for retrieving parameters.
//
// Note that if there're multiple parameters with the same name, the parameters are retrieved and overwrote
// in order of priority: router < query < form < body < custom.
func (r *Request) GetRequest(key string, def ...interface{}) interface{} {
v := r.GetRouterValue(key)
if v == nil {
r.ParseQuery()
if len(r.queryMap) > 0 {
v, _ = r.queryMap[key]
value := r.GetParam(key)
if value == nil {
r.ParseBody()
if len(r.bodyMap) > 0 {
value = r.bodyMap[key]
}
}
if v == nil {
v = r.GetPost(key)
if value == nil {
value = r.GetForm(key)
}
if v == nil {
v = r.GetParam(key)
if value == nil {
value = r.GetQuery(key)
}
if v != nil {
return v
if value == nil {
value = r.GetRouterValue(key)
}
if value != nil {
return value
}
if len(def) > 0 {
return def[0]
}
return v
return value
}
// GetRequestVar retrieves and returns the parameter named <key> passed from client as *gvar.Var,
@ -155,26 +161,70 @@ func (r *Request) GetRequestInterfaces(key string, def ...interface{}) []interfa
// GetRequestMap retrieves and returns all parameters passed from client as map,
// no matter what HTTP method the client is using. The parameter <kvMap> specifies the keys
// retrieving from client parameters, the associated values are the default values if the client
// does not pass.
// does not pass the according keys.
//
// GetRequestMap is one of the most commonly used functions for retrieving parameters.
//
// Note that if there're multiple parameters with the same name, the parameters are retrieved and overwrote
// in order of priority: router < query < form < body < custom.
func (r *Request) GetRequestMap(kvMap ...map[string]interface{}) map[string]interface{} {
r.ParseQuery()
r.ParseForm()
r.ParseBody()
m := make(map[string]interface{}, len(r.queryMap)+len(r.formMap)+len(r.bodyMap))
var ok, filter bool
var length int
if len(kvMap) > 0 && kvMap[0] != nil {
length = len(kvMap[0])
filter = true
} else {
length = len(r.routerMap) + len(r.queryMap) + len(r.formMap) + len(r.bodyMap) + len(r.paramsMap)
}
m := make(map[string]interface{}, length)
for k, v := range r.routerMap {
if filter {
if _, ok = kvMap[0][k]; !ok {
continue
}
}
m[k] = v
}
for k, v := range r.queryMap {
if filter {
if _, ok = kvMap[0][k]; !ok {
continue
}
}
m[k] = v
}
for k, v := range r.formMap {
if filter {
if _, ok = kvMap[0][k]; !ok {
continue
}
}
m[k] = v
}
for k, v := range r.bodyMap {
if filter {
if _, ok = kvMap[0][k]; !ok {
continue
}
}
m[k] = v
}
if len(kvMap) > 0 && kvMap[0] != nil {
var ok bool
for k, _ := range m {
for k, v := range r.paramsMap {
if filter {
if _, ok = kvMap[0][k]; !ok {
delete(m, k)
continue
}
}
m[k] = v
}
// Check none exist parameters and assign it with default value.
if filter {
for k, v := range kvMap[0] {
if _, ok = m[k]; !ok {
m[k] = v
}
}
}
@ -188,7 +238,7 @@ func (r *Request) GetRequestMap(kvMap ...map[string]interface{}) map[string]inte
func (r *Request) GetRequestMapStrStr(kvMap ...map[string]interface{}) map[string]string {
requestMap := r.GetRequestMap(kvMap...)
if len(requestMap) > 0 {
m := make(map[string]string)
m := make(map[string]string, len(requestMap))
for k, v := range requestMap {
m[k] = gconv.String(v)
}
@ -204,7 +254,7 @@ func (r *Request) GetRequestMapStrStr(kvMap ...map[string]interface{}) map[strin
func (r *Request) GetRequestMapStrVar(kvMap ...map[string]interface{}) map[string]*gvar.Var {
requestMap := r.GetRequestMap(kvMap...)
if len(requestMap) > 0 {
m := make(map[string]*gvar.Var)
m := make(map[string]*gvar.Var, len(requestMap))
for k, v := range requestMap {
m[k] = gvar.New(v)
}

View File

@ -26,62 +26,72 @@ import (
const (
gDEFAULT_HTTP_ADDR = ":80" // Default listening port for HTTP.
gDEFAULT_HTTPS_ADDR = ":443" // Default listening port for HTTPS.
URI_TYPE_DEFAULT = 0 // Type for method name to URI converting, which converts name to its lower case and joins the words using char '-'.
URI_TYPE_FULLNAME = 1 // Type for method name to URI converting, which does no converting to the method name.
URI_TYPE_ALLLOWER = 2 // Type for method name to URI converting, which converts name to its lower case.
URI_TYPE_CAMEL = 3 // Type for method name to URI converting, which converts name to its camel case.
URI_TYPE_DEFAULT = 0 // Method name to URI converting type, which converts name to its lower case and joins the words using char '-'.
URI_TYPE_FULLNAME = 1 // Method name to URI converting type, which does no converting to the method name.
URI_TYPE_ALLLOWER = 2 // Method name to URI converting type, which converts name to its lower case.
URI_TYPE_CAMEL = 3 // Method name to URI converting type, which converts name to its camel case.
)
// HTTP Server configuration.
type ServerConfig struct {
Address string // Server listening address like ":port", multiple addresses joining using ','
HTTPSAddr string // HTTPS addresses, multiple addresses joining using char ','.
HTTPSCertPath string // HTTPS certification file path.
HTTPSKeyPath string // HTTPS key file path.
Handler http.Handler // Default request handler function.
ReadTimeout time.Duration // Maximum duration for reading the entire request, including the body.
WriteTimeout time.Duration // Maximum duration before timing out writes of the response.
IdleTimeout time.Duration // Maximum amount of time to wait for the next request when keep-alives are enabled.
MaxHeaderBytes int // Maximum number of bytes the server will read parsing the request header's keys and values, including the request line.
TLSConfig *tls.Config // TLS configuration for use by ServeTLS and ListenAndServeTLS.
KeepAlive bool // HTTP keep-alive are enabled or not.
ServerAgent string // Server Agent.
View *gview.View // View engine for the server.
Rewrites map[string]string // URI rewrite rules.
IndexFiles []string // Static: 默认访问的文件列表
IndexFolder bool // Static: 如果访问目录是否显示目录列表
ServerRoot string // Static: 服务器服务的本地目录根路径(检索优先级比StaticPaths低)
SearchPaths []string // Static: 静态文件搜索目录(包含ServerRoot按照优先级进行排序)
StaticPaths []staticPathItem // Static: 静态文件目录映射(按照优先级进行排序)
FileServerEnabled bool // Static: 是否允许静态文件服务(通过静态文件服务方法调用自动识别)
CookieMaxAge time.Duration // Cookie: 有效期
CookiePath string // Cookie: 有效Path(注意同时也会影响SessionID)
CookieDomain string // Cookie: 有效Domain(注意同时也会影响SessionID)
SessionMaxAge time.Duration // Session: 有效期
SessionIdName string // Session: SessionId.
SessionPath string // Session: Session Storage path for storing session files.
SessionStorage gsession.Storage // Session: Session Storage implementer.
DenyIps []string // Security: 不允许访问的ip列表支持ip前缀过滤如: 10 将不允许10开头的ip访问
AllowIps []string // Security: 仅允许访问的ip列表支持ip前缀过滤如: 10 将仅允许10开头的ip访问
DenyRoutes []string // Security: 不允许访问的路由规则列表
Logger *glog.Logger // Logging: Custom logger for server.
LogPath string // Logging: 存放日志的目录路径(默认为空,表示不写文件)
LogStdout bool // Logging: 是否打印日志到终端(默认开启)
ErrorStack bool // Logging: 当产生错误时打印调用链详细堆栈
ErrorLogEnabled bool // Logging: 是否开启error log(默认开启)
ErrorLogPattern string // Logging: Error log file pattern like: error-{Ymd}.log
AccessLogEnabled bool // Logging: 是否开启access log(默认关闭)
AccessLogPattern string // Logging: Error log file pattern like: access-{Ymd}.log
PProfEnabled bool // PProf: Enable PProf feature or not.
PProfPattern string // PProf: PProf pattern for router, it enables PProf feature if it's not empty.
FormParsingMemory int64 // Mess: 表单解析内存限制(byte)
NameToUriType int // Mess: 服务注册时对象和方法名称转换为URI时的规则
GzipContentTypes []string // Mess: 允许进行gzip压缩的文件类型
DumpRouteMap bool // Mess: 是否在程序启动时默认打印路由表信息
RouterCacheExpire int // Mess: 路由检索缓存过期时间(秒)
// Basic
Address string // Server listening address like ":port", multiple addresses joined using ','.
HTTPSAddr string // HTTPS addresses, multiple addresses joined using char ','.
HTTPSCertPath string // HTTPS certification file path.
HTTPSKeyPath string // HTTPS key file path.
TLSConfig *tls.Config // TLS configuration for use by ServeTLS and ListenAndServeTLS.
Handler http.Handler // Request handler.
ReadTimeout time.Duration // Maximum duration for reading the entire request, including the body.
WriteTimeout time.Duration // Maximum duration before timing out writes of the response.
IdleTimeout time.Duration // Maximum amount of time to wait for the next request when keep-alive is enabled.
MaxHeaderBytes int // Maximum number of bytes the server will read parsing the request header's keys and values, including the request line.
KeepAlive bool // Enable HTTP keep-alive.
ServerAgent string // Server Agent.
View *gview.View // View object for the server.
// Static
Rewrites map[string]string // URI rewrite rules map.
IndexFiles []string // The index files for static folder.
IndexFolder bool // Whether list sub-files when requesting folder; server responses HTTP status code 403 if it's false.
ServerRoot string // The root directory for static service.
SearchPaths []string // Additional searching directories for static service.
StaticPaths []staticPathItem // URI to directory mapping array.
FileServerEnabled bool // Switch for static service.
// Cookie
CookieMaxAge time.Duration // Max TTL for cookie items.
CookiePath string // Cookie Path(also affects the default storage for session id).
CookieDomain string // Cookie Domain(also affects the default storage for session id).
// Session
SessionMaxAge time.Duration // Max TTL for session items.
SessionIdName string // Session id name.
SessionPath string // Session Storage directory path for storing session files.
SessionStorage gsession.Storage // Session Storage implementer.
// Logging
Logger *glog.Logger // Logger for server.
LogPath string // Directory for storing logging files.
LogStdout bool // Printing logging content to stdout.
ErrorStack bool // Logging stack information when error.
ErrorLogEnabled bool // Enable error logging files.
ErrorLogPattern string // Error log file pattern like: error-{Ymd}.log
AccessLogEnabled bool // Enable access logging files.
AccessLogPattern string // Error log file pattern like: access-{Ymd}.log
// PProf
PProfEnabled bool // Enable PProf feature.
PProfPattern string // PProf service pattern for router, it automatically enables PProf feature if called.
// Other
FormParsingMemory int64 // 表单解析内存限制(byte)
NameToUriType int // 服务注册时对象和方法名称转换为URI时的规则
GzipContentTypes []string // 允许进行gzip压缩的文件类型
DumpRouteMap bool // 是否在程序启动时默认打印路由表信息
RouterCacheExpire int // 路由检索缓存过期时间(秒)
}
// 默认HTTP Server配置
// defaultServerConfig is the default configuration object for server.
var defaultServerConfig = ServerConfig{
Address: "",
HTTPSAddr: "",

View File

@ -6,18 +6,6 @@
package ghttp
func (s *Server) SetDenyIps(ips []string) {
s.config.DenyIps = ips
}
func (s *Server) SetAllowIps(ips []string) {
s.config.AllowIps = ips
}
func (s *Server) SetDenyRoutes(routes []string) {
s.config.DenyRoutes = routes
}
// 设置URI重写规则
func (s *Server) SetRewrite(uri string, rewrite string) {
s.config.Rewrites[uri] = rewrite

View File

@ -403,3 +403,44 @@ func Test_Params_Basic(t *testing.T) {
gtest.Assert(client.PostContent("/struct-with-base", `id=1&name=john&password1=123&password2=456`), "1john1234561john123456")
})
}
func Test_Params_Priority(t *testing.T) {
p := ports.PopRand()
s := g.Server(p)
s.BindHandler("/query", func(r *ghttp.Request) {
r.Response.Write(r.GetQuery("a"))
})
s.BindHandler("/post", func(r *ghttp.Request) {
r.Response.Write(r.GetPost("a"))
})
s.BindHandler("/form", func(r *ghttp.Request) {
r.Response.Write(r.GetForm("a"))
})
s.BindHandler("/request", func(r *ghttp.Request) {
r.Response.Write(r.Get("a"))
})
s.BindHandler("/request-map", func(r *ghttp.Request) {
r.Response.Write(r.GetMap(g.Map{
"a": 1,
"b": 2,
}))
})
s.SetPort(p)
s.SetDumpRouteMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.Case(t, func() {
prefix := fmt.Sprintf("http://127.0.0.1:%d", p)
client := ghttp.NewClient()
client.SetPrefix(prefix)
gtest.Assert(client.GetContent("/query?a=1", "a=100"), "100")
gtest.Assert(client.PostContent("/post?a=1", "a=100"), "100")
gtest.Assert(client.PostContent("/form?a=1", "a=100"), "100")
gtest.Assert(client.PutContent("/form?a=1", "a=100"), "100")
gtest.Assert(client.GetContent("/request?a=1", "a=100"), "100")
gtest.Assert(client.GetContent("/request-map?a=1&b=2&c=3", "a=100&b=200&c=300"), `{"a":"100","b":"200"}`)
})
}

View File

@ -16,7 +16,6 @@ import (
"github.com/gogf/gf/test/gtest"
)
// 基本路由功能测试
func Test_Router_Basic(t *testing.T) {
p := ports.PopRand()
s := g.Server(p)