mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
This pull request standardizes the use of the Go 1.18+ `any` type alias
instead of `interface{}` throughout the codebase. The change improves
code readability and aligns with modern Go best practices. The update
touches many files, including core data structures, code generation
templates, logging utilities, and test data, ensuring consistency across
all usages.
**Type alias migration to `any`:**
* Replaced all instances of `interface{}` with `any` in core data
structures such as `garray` and in generated model structs (e.g.,
`TableUser`, `User1`, `User2`) to modernize type usage.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
* Updated function signatures, method parameters, and return types from
`interface{}` to `any` in various parts of the codebase, including code
generation, service logic, and logging utilities (e.g., `mlog`).
[[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74)
[[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)
[[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107)
[[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121)
[[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112)
[[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36)
[[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74)
[[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96)
**Generated code and templates:**
* Adjusted generated files and code generation templates to output `any`
instead of `interface{}` for relevant struct fields and function
signatures, ensuring that new code generation aligns with the updated
convention.
[[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
[[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)
**Container and utility updates:**
* Refactored the `garray` container implementation and related
constructors/methods to use `[]any` instead of `[]interface{}`, along
with corresponding function signatures.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52)
[[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62)
[[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86)
[[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97)
[[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114)
[[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124)
[[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143)
[[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167)
These changes collectively modernize the codebase and prepare it for
future Go developments by using the idiomatic `any` type.
286 lines
9.6 KiB
Go
286 lines
9.6 KiB
Go
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
//
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
// If a copy of the MIT was not distributed with this file,
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
package ghttp
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gogf/gf/v2/internal/intlog"
|
|
"github.com/gogf/gf/v2/os/gres"
|
|
"github.com/gogf/gf/v2/os/gsession"
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
"github.com/gogf/gf/v2/os/gview"
|
|
"github.com/gogf/gf/v2/text/gregex"
|
|
"github.com/gogf/gf/v2/text/gstr"
|
|
"github.com/gogf/gf/v2/util/guid"
|
|
)
|
|
|
|
// Request is the context object for a request.
|
|
type Request struct {
|
|
*http.Request
|
|
Server *Server // Server.
|
|
Cookie *Cookie // Cookie.
|
|
Session *gsession.Session // Session.
|
|
Response *Response // Corresponding Response of this request.
|
|
Router *Router // Matched Router for this request. Note that it's not available in HOOK handler.
|
|
EnterTime *gtime.Time // Request starting time in milliseconds.
|
|
LeaveTime *gtime.Time // Request to end time in milliseconds.
|
|
Middleware *middleware // Middleware manager.
|
|
StaticFile *staticFile // Static file object for static file serving.
|
|
|
|
// =================================================================================================================
|
|
// Private attributes for internal usage purpose.
|
|
// =================================================================================================================
|
|
|
|
handlers []*HandlerItemParsed // All matched handlers containing handler, hook and middleware for this request.
|
|
serveHandler *HandlerItemParsed // Real business handler serving for this request, not hook or middleware handler.
|
|
handlerResponse any // Handler response object for Request/Response handler.
|
|
hasHookHandler bool // A bool marking whether there's hook handler in the handlers for performance purpose.
|
|
hasServeHandler bool // A bool marking whether there's serving handler in the handlers for performance purpose.
|
|
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]any // Custom parameters map.
|
|
routerMap map[string]string // Router parameters map, which might be nil if there are no router parameters.
|
|
queryMap map[string]any // Query parameters map, which is nil if there's no query string.
|
|
formMap map[string]any // Form parameters map, which is nil if there's no form of data from the client.
|
|
bodyMap map[string]any // Body parameters map, which might be nil if their nobody content.
|
|
error error // Current executing error of the request.
|
|
exitAll bool // A bool marking whether current request is exited.
|
|
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.
|
|
isFileRequest bool // A bool marking whether current request is file serving.
|
|
viewObject *gview.View // Custom template view engine object for this response.
|
|
viewParams gview.Params // Custom template view variables for this response.
|
|
originUrlPath string // Original URL path that passed from client.
|
|
}
|
|
|
|
// staticFile is the file struct for static file service.
|
|
type staticFile struct {
|
|
File *gres.File // Resource file object.
|
|
Path string // File path.
|
|
IsDir bool // Is directory.
|
|
}
|
|
|
|
// newRequest creates and returns a new request object.
|
|
func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request {
|
|
request := &Request{
|
|
Server: s,
|
|
Request: r,
|
|
Response: newResponse(s, w),
|
|
EnterTime: gtime.Now(),
|
|
originUrlPath: r.URL.Path,
|
|
}
|
|
request.Cookie = GetCookie(request)
|
|
request.Session = s.sessionManager.New(
|
|
r.Context(),
|
|
request.GetSessionId(),
|
|
)
|
|
request.Response.Request = request
|
|
request.Middleware = &middleware{
|
|
request: request,
|
|
}
|
|
// Custom session id creating function.
|
|
err := request.Session.SetIdFunc(func(ttl time.Duration) string {
|
|
var (
|
|
address = request.RemoteAddr
|
|
header = fmt.Sprintf("%v", request.Header)
|
|
)
|
|
intlog.Print(r.Context(), address, header)
|
|
return guid.S([]byte(address), []byte(header))
|
|
})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
// Remove char '/' in the tail of URI.
|
|
if request.URL.Path != "/" {
|
|
for len(request.URL.Path) > 0 && request.URL.Path[len(request.URL.Path)-1] == '/' {
|
|
request.URL.Path = request.URL.Path[:len(request.URL.Path)-1]
|
|
}
|
|
}
|
|
|
|
// Default URI value if it's empty.
|
|
if request.URL.Path == "" {
|
|
request.URL.Path = "/"
|
|
}
|
|
return request
|
|
}
|
|
|
|
// WebSocket upgrades current request as a websocket request.
|
|
// It returns a new WebSocket object if success, or the error if failure.
|
|
// Note that the request should be a websocket request, or it will surely fail upgrading.
|
|
//
|
|
// Deprecated: will be removed in the future, please use third-party websocket library instead.
|
|
func (r *Request) WebSocket() (*WebSocket, error) {
|
|
if conn, err := wsUpGrader.Upgrade(r.Response.Writer, r.Request, nil); err == nil {
|
|
return &WebSocket{
|
|
conn,
|
|
}, nil
|
|
} else {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Exit exits executing of current HTTP handler.
|
|
func (r *Request) Exit() {
|
|
panic(exceptionExit)
|
|
}
|
|
|
|
// ExitAll exits executing of current and following HTTP handlers.
|
|
func (r *Request) ExitAll() {
|
|
r.exitAll = true
|
|
panic(exceptionExitAll)
|
|
}
|
|
|
|
// ExitHook exits executing of current and following HTTP HOOK handlers.
|
|
func (r *Request) ExitHook() {
|
|
panic(exceptionExitHook)
|
|
}
|
|
|
|
// IsExited checks and returns whether current request is exited.
|
|
func (r *Request) IsExited() bool {
|
|
return r.exitAll
|
|
}
|
|
|
|
// GetHeader retrieves and returns the header value with given `key`.
|
|
// It returns the optional `def` parameter if the header does not exist.
|
|
func (r *Request) GetHeader(key string, def ...string) string {
|
|
value := r.Header.Get(key)
|
|
if value == "" && len(def) > 0 {
|
|
value = def[0]
|
|
}
|
|
return value
|
|
}
|
|
|
|
// GetHost returns current request host name, which might be a domain or an IP without port.
|
|
func (r *Request) GetHost() string {
|
|
if len(r.parsedHost) == 0 {
|
|
array, _ := gregex.MatchString(`(.+):(\d+)`, r.Host)
|
|
if len(array) > 1 {
|
|
r.parsedHost = array[1]
|
|
} else {
|
|
r.parsedHost = r.Host
|
|
}
|
|
}
|
|
return r.parsedHost
|
|
}
|
|
|
|
// IsFileRequest checks and returns whether current request is serving file.
|
|
func (r *Request) IsFileRequest() bool {
|
|
return r.isFileRequest
|
|
}
|
|
|
|
// IsAjaxRequest checks and returns whether current request is an AJAX request.
|
|
func (r *Request) IsAjaxRequest() bool {
|
|
return strings.EqualFold(r.Header.Get("X-Requested-With"), "XMLHttpRequest")
|
|
}
|
|
|
|
// 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 r.clientIp != "" {
|
|
return r.clientIp
|
|
}
|
|
realIps := r.Header.Get("X-Forwarded-For")
|
|
if realIps != "" && len(realIps) != 0 && !strings.EqualFold("unknown", realIps) {
|
|
ipArray := strings.Split(realIps, ",")
|
|
r.clientIp = ipArray[0]
|
|
}
|
|
if r.clientIp == "" {
|
|
r.clientIp = r.Header.Get("Proxy-Client-IP")
|
|
}
|
|
if r.clientIp == "" {
|
|
r.clientIp = r.Header.Get("WL-Proxy-Client-IP")
|
|
}
|
|
if r.clientIp == "" {
|
|
r.clientIp = r.Header.Get("HTTP_CLIENT_IP")
|
|
}
|
|
if r.clientIp == "" {
|
|
r.clientIp = r.Header.Get("HTTP_X_FORWARDED_FOR")
|
|
}
|
|
if r.clientIp == "" {
|
|
r.clientIp = r.Header.Get("X-Real-IP")
|
|
}
|
|
if r.clientIp == "" {
|
|
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 strings.Trim(array[1], "[]")
|
|
}
|
|
return r.RemoteAddr
|
|
}
|
|
|
|
// GetSchema returns the schema of this request.
|
|
func (r *Request) GetSchema() string {
|
|
var (
|
|
scheme = "http"
|
|
proto = r.Header.Get("X-Forwarded-Proto")
|
|
)
|
|
if r.TLS != nil || gstr.Equal(proto, "https") {
|
|
scheme = "https"
|
|
}
|
|
return scheme
|
|
}
|
|
|
|
// GetUrl returns current URL of this request.
|
|
func (r *Request) GetUrl() string {
|
|
var (
|
|
scheme = "http"
|
|
proto = r.Header.Get("X-Forwarded-Proto")
|
|
)
|
|
|
|
if r.TLS != nil || gstr.Equal(proto, "https") {
|
|
scheme = "https"
|
|
}
|
|
return fmt.Sprintf(`%s://%s%s`, scheme, r.Host, r.URL.String())
|
|
}
|
|
|
|
// GetSessionId retrieves and returns session id from cookie or header.
|
|
func (r *Request) GetSessionId() string {
|
|
id := r.Cookie.GetSessionId()
|
|
if id == "" {
|
|
id = r.Header.Get(r.Server.GetSessionIdName())
|
|
}
|
|
return id
|
|
}
|
|
|
|
// GetReferer returns referer of this request.
|
|
func (r *Request) GetReferer() string {
|
|
return r.Header.Get("Referer")
|
|
}
|
|
|
|
// GetError returns the error occurs in the procedure of the request.
|
|
// It returns nil if there's no error.
|
|
func (r *Request) GetError() error {
|
|
return r.error
|
|
}
|
|
|
|
// SetError sets custom error for current request.
|
|
func (r *Request) SetError(err error) {
|
|
r.error = err
|
|
}
|
|
|
|
// ReloadParam is used for modifying request parameter.
|
|
// Sometimes, we want to modify request parameters through middleware, but directly modifying Request.Body
|
|
// is invalid, so it clears the parsed* marks of Request to make the parameters reparsed.
|
|
func (r *Request) ReloadParam() {
|
|
r.parsedBody = false
|
|
r.parsedForm = false
|
|
r.parsedQuery = false
|
|
r.bodyContent = nil
|
|
}
|