Skip to content

Commit 360dbf3

Browse files
committed
refactor(net/gclient): 重构HTTP请求参数处理逻辑
- 提取URL参数解析逻辑到独立函数parseUnEncodedParams - 提取查询字符串构建逻辑到独立函数buildUnEncodedQuery - 添加getMediaType方法安全解析Content-Type头部 - 将上下文参数传递给相关请求构建函数 - 移除重复的参数合并代码并优化流程 - 添加内部日志记录用于调试目的
1 parent 7401ec5 commit 360dbf3

File tree

1 file changed

+81
-44
lines changed

1 file changed

+81
-44
lines changed

net/gclient/gclient_request.go

Lines changed: 81 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/gogf/gf/v2/errors/gcode"
2525
"github.com/gogf/gf/v2/errors/gerror"
2626
"github.com/gogf/gf/v2/internal/httputil"
27+
"github.com/gogf/gf/v2/internal/intlog"
2728
"github.com/gogf/gf/v2/internal/json"
2829
"github.com/gogf/gf/v2/internal/utils"
2930
"github.com/gogf/gf/v2/os/gfile"
@@ -195,29 +196,19 @@ func (c *Client) mergeQueryParams(u string, dataParams string) (string, error) {
195196

196197
// Merge data parameters (for GET requests with default Content-Type)
197198
if dataParams != "" {
198-
// Handle noUrlEncode flag: if noUrlEncode is true, parse data params manually
199-
// to avoid double encoding/decoding issues
199+
var dataValues url.Values
200200
if c.noUrlEncode {
201-
// Split params by & and add them without URL encoding
202-
for _, pair := range strings.Split(dataParams, "&") {
203-
if pair == "" {
204-
continue
205-
}
206-
parts := strings.SplitN(pair, "=", 2)
207-
if len(parts) == 2 {
208-
// Data params override URL params
209-
queryValues[parts[0]] = []string{parts[1]}
210-
}
211-
}
201+
// Parse params without URL decoding to avoid double encoding/decoding issues
202+
dataValues = parseUnEncodedParams(dataParams)
212203
} else {
213-
dataValues, err := url.ParseQuery(dataParams)
204+
dataValues, err = url.ParseQuery(dataParams)
214205
if err != nil {
215206
return "", gerror.Wrapf(err, `url.ParseQuery failed for data params "%s"`, dataParams)
216207
}
217-
for k, v := range dataValues {
218-
// Data params override URL params
219-
queryValues[k] = v
220-
}
208+
}
209+
// Data params override URL params
210+
for k, v := range dataValues {
211+
queryValues[k] = v
221212
}
222213
}
223214

@@ -265,18 +256,7 @@ func (c *Client) mergeQueryParams(u string, dataParams string) (string, error) {
265256
// Update URL with merged parameters
266257
// Respect noUrlEncode flag
267258
if c.noUrlEncode {
268-
// Manually build query string without encoding
269-
var queryParts []string
270-
for k, values := range queryValues {
271-
for _, v := range values {
272-
if v == "" {
273-
queryParts = append(queryParts, k)
274-
} else {
275-
queryParts = append(queryParts, k+"="+v)
276-
}
277-
}
278-
}
279-
parsedURL.RawQuery = strings.Join(queryParts, "&")
259+
parsedURL.RawQuery = buildUnEncodedQuery(queryValues)
280260
} else {
281261
parsedURL.RawQuery = queryValues.Encode()
282262
}
@@ -295,22 +275,82 @@ func (c *Client) normalizeURL(u string) string {
295275
return u
296276
}
297277

278+
// getMediaType safely parses the Content-Type header and returns the media type.
279+
// If parsing fails, it logs the error and returns the raw header value as fallback.
280+
func (c *Client) getMediaType(ctx context.Context) string {
281+
contentType := c.header[httpHeaderContentType]
282+
if contentType == "" {
283+
return ""
284+
}
285+
286+
mediaType, _, err := mime.ParseMediaType(contentType)
287+
if err != nil {
288+
// Log the parsing error for debugging purposes
289+
intlog.Errorf(ctx,
290+
`mime.ParseMediaType failed for Content-Type "%s": %v, using raw value as fallback`,
291+
contentType, err,
292+
)
293+
return contentType
294+
}
295+
return mediaType
296+
}
297+
298+
// parseUnEncodedParams parses URL-encoded parameter string without decoding.
299+
// This is used when noUrlEncode flag is true to avoid double encoding/decoding.
300+
// It splits the params by '&' and '=' and returns a url.Values map.
301+
func parseUnEncodedParams(params string) url.Values {
302+
values := make(url.Values)
303+
if params == "" {
304+
return values
305+
}
306+
307+
for _, pair := range strings.Split(params, "&") {
308+
if pair == "" {
309+
continue
310+
}
311+
parts := strings.SplitN(pair, "=", 2)
312+
if len(parts) == 2 {
313+
values[parts[0]] = []string{parts[1]}
314+
} else if len(parts) == 1 {
315+
// Handle key without value (e.g., "?flag")
316+
values[parts[0]] = []string{""}
317+
}
318+
}
319+
return values
320+
}
321+
322+
// buildUnEncodedQuery builds a query string from url.Values without encoding.
323+
// This is used when noUrlEncode flag is true.
324+
func buildUnEncodedQuery(values url.Values) string {
325+
if len(values) == 0 {
326+
return ""
327+
}
328+
329+
var queryParts []string
330+
for k, vals := range values {
331+
for _, v := range vals {
332+
if v == "" {
333+
queryParts = append(queryParts, k)
334+
} else {
335+
queryParts = append(queryParts, k+"="+v)
336+
}
337+
}
338+
}
339+
return strings.Join(queryParts, "&")
340+
}
341+
298342
// buildRequestParams converts data to request parameters based on Content-Type.
299343
// It returns:
300344
// - params: serialized parameter string
301345
// - allowFileUploading: whether file uploading is allowed for this request
302346
// - err: error if serialization fails
303-
func (c *Client) buildRequestParams(data ...any) (params string, allowFileUploading bool, err error) {
347+
func (c *Client) buildRequestParams(ctx context.Context, data ...any) (params string, allowFileUploading bool, err error) {
304348
allowFileUploading = true
305349
if len(data) == 0 {
306350
return "", allowFileUploading, nil
307351
}
308352

309-
mediaType, _, err := mime.ParseMediaType(c.header[httpHeaderContentType])
310-
if err != nil {
311-
// Fallback: use the raw header value if parsing fails.
312-
mediaType = c.header[httpHeaderContentType]
313-
}
353+
mediaType := c.getMediaType(ctx)
314354

315355
switch mediaType {
316356
case httpHeaderContentTypeJson:
@@ -495,14 +535,10 @@ func (c *Client) createMultipartRequest(method, u string, params string) (*http.
495535

496536
// createGetRequest creates http.Request for GET method.
497537
// It merges query parameters and handles different Content-Types.
498-
func (c *Client) createGetRequest(u string, params string) (*http.Request, error) {
538+
func (c *Client) createGetRequest(ctx context.Context, u string, params string) (*http.Request, error) {
499539
var bodyBuffer *bytes.Buffer
500540
if params != "" {
501-
mediaType, _, err := mime.ParseMediaType(c.header[httpHeaderContentType])
502-
if err != nil {
503-
// Fallback: use the raw header value if parsing fails.
504-
mediaType = c.header[httpHeaderContentType]
505-
}
541+
mediaType := c.getMediaType(ctx)
506542
switch mediaType {
507543
case
508544
httpHeaderContentTypeJson,
@@ -511,6 +547,7 @@ func (c *Client) createGetRequest(u string, params string) (*http.Request, error
511547
default:
512548
// Merge all query parameters before creating http.Request
513549
// This includes: URL params + data params + c.queryParams
550+
var err error
514551
if u, err = c.mergeQueryParams(u, params); err != nil {
515552
return nil, err
516553
}
@@ -556,14 +593,14 @@ func (c *Client) prepareRequest(ctx context.Context, method, u string, data ...a
556593
u = c.normalizeURL(u)
557594

558595
// 2. Build request parameters
559-
params, allowFileUploading, err := c.buildRequestParams(data...)
596+
params, allowFileUploading, err := c.buildRequestParams(ctx, data...)
560597
if err != nil {
561598
return nil, err
562599
}
563600

564601
// 3. Create request based on method
565602
if method == http.MethodGet {
566-
req, err = c.createGetRequest(u, params)
603+
req, err = c.createGetRequest(ctx, u, params)
567604
} else {
568605
req, err = c.createPostRequest(method, u, params, allowFileUploading)
569606
}

0 commit comments

Comments
 (0)