Repository: gogf/gf

Issue:
net/ghttp: Param in header would affect the following params parse
### Go version

go version go1.23.2 windows/amd64

### GoFrame version

2.9.0

### Can this bug be reproduced with the latest release?

Option Yes

### What did you do?

Initial web project with the latest version and modify the `HelloReq` to :

```
type HelloReq struct {
  g.Meta  `path:"/hello" tags:"Project" method:"get" sum:"List all projects"`
  Token   string `json:"Authorization" des:"JWT" in:"header"`
  Owned   bool   `json:"owned" in:"query" default:"false"`
  Deleted bool   `json:"deleted" in:"query" default:"false"`
}
```

Send the request and dump req in controller

```
curl --location 'http://localhost:8000/hello?deleted=false' \
--header 'Authorization: 1'
```

### What did you see happen?

The dump info would show:

```
{
    Token:   "1",
    Owned:   true,
    Deleted: false,
}
```


### What did you expect to see?

In the previous version (2.8.3), it was:
```
{
    Token:   "1",
    Owned:   false,
    Deleted: false,
}
```

Or if you move the Token to the end of the structure, it would also have the right dump:
```
{
    Owned:   false,
    Deleted: false,
    Token:   "1",
}
```

Seems some changes was made with the param parse? Haven't locate the bug yet, may be gconv related

Discussion:
@UncleChair: https://github.com/gogf/gf/blob/fee38b4531224b929c095ef643a68a92bbad3d4b/net/ghttp/ghttp_request_param_request.go#L241-L254

@gqcn Missing in query check here, seems related to #4182 ?

Solution patch:
diff --git a/net/ghttp/ghttp_request_param_request.go b/net/ghttp/ghttp_request_param_request.go
index 5c7ebd0b1..31e3b83d7 100644
--- a/net/ghttp/ghttp_request_param_request.go
+++ b/net/ghttp/ghttp_request_param_request.go
@@ -222,10 +222,8 @@ func (r *Request) mergeInTagStructValue(data map[string]any) error {
 	fields := r.serveHandler.Handler.Info.ReqStructFields
 	if len(fields) > 0 {
 		var (
-			foundKey   string
-			foundValue any
-			headerMap  = make(map[string]any)
-			cookieMap  = make(map[string]any)
+			headerMap = make(map[string]any)
+			cookieMap = make(map[string]any)
 		)
 
 		for k, v := range r.Header {
@@ -239,6 +237,10 @@ func (r *Request) mergeInTagStructValue(data map[string]any) error {
 		}
 
 		for _, field := range fields {
+			var (
+				foundKey   string
+				foundValue any
+			)
 			if tagValue := field.TagIn(); tagValue != "" {
 				findKey := field.TagPriorityName()
 				switch tagValue {



Test patch:
diff --git a/net/ghttp/ghttp_z_unit_issue_test.go b/net/ghttp/ghttp_z_unit_issue_test.go
index a9d6a01bc..fa35f5e4f 100644
--- a/net/ghttp/ghttp_z_unit_issue_test.go
+++ b/net/ghttp/ghttp_z_unit_issue_test.go
@@ -726,3 +726,61 @@ func Test_Issue4093(t *testing.T) {
 		t.Assert(client.PostContent(ctx, "/test"), `{"page":1,"pageSize":10,"pagination":true,"name":"john","number":1}`)
 	})
 }
+
+// Issue4227Req
+type Issue4227Req struct {
+	g.Meta      `path:"/hello/:path_param" method:"post"`
+	HeaderParam string `json:"Authorization" in:"header" default:"Bearer token123"`
+	QueryParam  bool   `json:"query_param" in:"query" default:"false"`
+	PathParam   int    `json:"path_param" in:"path" default:"123" v:"required"`
+	CookieParam bool   `json:"cookie_param" in:"cookie" default:"false"`
+	BodyParam   bool   `json:"body_param" default:"false"`
+}
+
+type Issue4227Res struct {
+	g.Meta `mime:"application/json"`
+}
+
+var (
+	Issue4227 = cIssue4227{}
+)
+
+type cIssue4227 struct{}
+
+func (c *cIssue4227) Feature(ctx context.Context, req *Issue4227Req) (res *Issue4227Res, err error) {
+	g.RequestFromCtx(ctx).Response.WriteJson(req)
+	return
+}
+
+// https://github.com/gogf/gf/issues/4227
+func Test_Issue4227(t *testing.T) {
+	s := g.Server(guid.S())
+	s.Group("/", func(group *ghttp.RouterGroup) {
+		group.Middleware(ghttp.MiddlewareHandlerResponse)
+		group.Bind(Issue4227)
+	})
+	s.SetDumpRouterMap(false)
+	s.Start()
+	defer s.Shutdown()
+
+	time.Sleep(100 * time.Millisecond)
+
+	gtest.C(t, func(t *gtest.T) {
+		prefix := fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())
+		client := g.Client().ContentJson()
+		client.SetPrefix(prefix)
+
+		resp1 := client.PostContent(ctx, "/hello/123", `{}`)
+		t.Assert(resp1, `{"Authorization":"Bearer token123","query_param":false,"path_param":123,"cookie_param":false,"body_param":false}`)
+
+		client.SetHeader("Authorization", "Bearer token123")
+
+		resp2 := client.PostContent(ctx, "/hello/123", `{"body_param":"true"}`)
+		t.Assert(resp2, `{"Authorization":"Bearer token123","query_param":false,"path_param":123,"cookie_param":false,"body_param":true}`)
+
+		client.SetCookie("cookie_param", "true")
+		resp3 := client.PostContent(ctx, "/hello/123", `{}`)
+		t.Assert(resp3, `{"Authorization":"Bearer token123","query_param":false,"path_param":123,"cookie_param":true,"body_param":false}`)
+
+	})
+}