1
0
mirror of https://github.com/silenceper/wechat.git synced 2026-02-04 12:52:27 +08:00

Compare commits

..

5 Commits

Author SHA1 Message Date
is-Xiaoen
30c8e77246 fix: improve type safety in httpWithTLS for custom RoundTripper (#861)
* fix: improve type safety in httpWithTLS for custom RoundTripper

Add type assertion check to handle cases where DefaultHTTPClient.Transport
is a custom http.RoundTripper implementation (not *http.Transport).

This improves upon the fix in PR #844 which only handled nil Transport.
The previous code would still panic if users set a custom RoundTripper:

  trans := baseTransport.(*http.Transport).Clone()  // panic if not *http.Transport

Now safely handles three scenarios:
1. Transport is nil -> use http.DefaultTransport
2. Transport is *http.Transport -> clone it
3. Transport is custom RoundTripper -> use http.DefaultTransport

Added comprehensive test cases:
- TestHttpWithTLS_NilTransport
- TestHttpWithTLS_CustomTransport
- TestHttpWithTLS_CustomRoundTripper

Related to #803

* refactor: reduce code duplication and complexity in httpWithTLS

- Eliminate duplicate http.DefaultTransport.Clone() calls
- Reduce cyclomatic complexity by simplifying conditional logic
- Use nil check pattern instead of nested else branches
- Maintain same functionality with cleaner code structure

This addresses golangci-lint warnings for dupl and gocyclo.

* fix: add newline at end of http_test.go

Fix gofmt -s compliance issue:
- File must end with newline character
- Addresses golangci-lint gofmt error on line 81

This fixes CI check failure.
2025-10-27 14:24:24 +08:00
mahongran
6f6e95cfdb SubscribeMsgSentList结构中的ErrorCode类型从int更新为string (#859) 2025-10-24 20:49:24 +08:00
silenceper
c806a0c172 Add star badge to README 2025-10-24 17:37:01 +08:00
zhangjiani
c136b878ce 调整企微回调URL参数tag,兼容kratos框架 (#855)
* fix: handle JSON parse error when API returns binary file instead of error JSON

* fix: add JSON tags to SignatureOptions struct fields for proper serialization

* fix: mod module

* fix: rollback

---------

Co-authored-by: tax <jia_deng@intsig.net>
2025-09-19 11:16:52 +08:00
zhangjiani
d4a81916d5 fix: handle JSON parse error when API returns binary file instead of error JSON (#852)
Co-authored-by: tax <jia_deng@intsig.net>
2025-09-14 19:47:00 +08:00
7 changed files with 116 additions and 18 deletions

View File

@@ -4,6 +4,8 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/silenceper/wechat/v2)](https://goreportcard.com/report/github.com/silenceper/wechat/v2)
[![pkg](https://img.shields.io/badge/dev-reference-007d9c?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/silenceper/wechat/v2?tab=doc)
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/silenceper/wechat?sort=semver)
![star](https://gitcode.com/silenceper/wechat/star/badge.svg)
使用Golang开发的微信SDK简单、易用。

View File

@@ -556,7 +556,7 @@ type SubscribeMsgSentEvent struct {
type SubscribeMsgSentList struct {
TemplateID string `xml:"TemplateId" json:"TemplateId"`
MsgID string `xml:"MsgID" json:"MsgID"`
ErrorCode int `xml:"ErrorCode" json:"ErrorCode"`
ErrorCode string `xml:"ErrorCode" json:"ErrorCode"`
ErrorStatus string `xml:"ErrorStatus" json:"ErrorStatus"`
}

View File

@@ -68,3 +68,18 @@ func DecodeWithError(response []byte, obj interface{}, apiName string) error {
}
return nil
}
// HandleFileResponse 通用处理微信等接口返回:有时 JSON 错误,有时文件内容
func HandleFileResponse(response []byte, apiName string) ([]byte, error) {
var commErr CommonError
if err := json.Unmarshal(response, &commErr); err == nil {
// 能解析成 JSON判断是否为错误
if commErr.ErrCode != 0 {
commErr.apiName = apiName
return nil, &commErr
}
// 能解析成 JSON 且没错误码,极少情况(比如微信返回的业务数据是 JSON 但无 errcode 字段),可根据需要调整
}
// 不能解析成 JSON或没错误码直接返回原始内容
return response, nil
}

View File

@@ -292,13 +292,19 @@ func httpWithTLS(rootCa, key string) (*http.Client, error) {
Certificates: []tls.Certificate{cert},
}
var baseTransport http.RoundTripper
// 安全地获取 *http.Transport
var trans *http.Transport
// 尝试从 DefaultHTTPClient 获取 Transport如果失败则使用默认值
if DefaultHTTPClient.Transport != nil {
baseTransport = DefaultHTTPClient.Transport
} else {
baseTransport = http.DefaultTransport
if t, ok := DefaultHTTPClient.Transport.(*http.Transport); ok {
trans = t.Clone()
}
}
trans := baseTransport.(*http.Transport).Clone()
// 如果无法获取有效的 Transport使用默认值
if trans == nil {
trans = http.DefaultTransport.(*http.Transport).Clone()
}
trans.TLSClientConfig = config
trans.DisableCompression = true
client = &http.Client{Transport: trans}

81
util/http_test.go Normal file
View File

@@ -0,0 +1,81 @@
package util
import (
"net/http"
"testing"
)
// TestHttpWithTLS_NilTransport tests the scenario where DefaultHTTPClient.Transport is nil
func TestHttpWithTLS_NilTransport(t *testing.T) {
// Save original transport
originalTransport := DefaultHTTPClient.Transport
defer func() {
DefaultHTTPClient.Transport = originalTransport
}()
// Set Transport to nil to simulate the bug scenario
DefaultHTTPClient.Transport = nil
// This should not panic after the fix
// Note: This will fail due to invalid cert path, but shouldn't panic on type assertion
_, err := httpWithTLS("./testdata/invalid_cert.p12", "password")
// We expect an error (cert file not found), but NOT a panic
if err == nil {
t.Error("Expected error due to invalid cert path, but got nil")
}
}
// TestHttpWithTLS_CustomTransport tests the scenario where DefaultHTTPClient has a custom Transport
func TestHttpWithTLS_CustomTransport(t *testing.T) {
// Save original transport
originalTransport := DefaultHTTPClient.Transport
defer func() {
DefaultHTTPClient.Transport = originalTransport
}()
// Set a custom http.Transport
customTransport := &http.Transport{
MaxIdleConns: 100,
}
DefaultHTTPClient.Transport = customTransport
// This should not panic
_, err := httpWithTLS("./testdata/invalid_cert.p12", "password")
// We expect an error (cert file not found), but NOT a panic
if err == nil {
t.Error("Expected error due to invalid cert path, but got nil")
}
}
// CustomRoundTripper is a custom implementation of http.RoundTripper
type CustomRoundTripper struct{}
func (c *CustomRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
return http.DefaultTransport.RoundTrip(req)
}
// TestHttpWithTLS_CustomRoundTripper tests the edge case where DefaultHTTPClient has a custom RoundTripper
// that is NOT *http.Transport
func TestHttpWithTLS_CustomRoundTripper(t *testing.T) {
// Save original transport
originalTransport := DefaultHTTPClient.Transport
defer func() {
DefaultHTTPClient.Transport = originalTransport
}()
// Set a custom RoundTripper that is NOT *http.Transport
customRoundTripper := &CustomRoundTripper{}
DefaultHTTPClient.Transport = customRoundTripper
// Create a recovery handler to catch potential panic
defer func() {
if r := recover(); r != nil {
t.Errorf("httpWithTLS panicked with custom RoundTripper: %v", r)
}
}()
// This might panic if the code doesn't handle non-*http.Transport RoundTripper properly
_, _ = httpWithTLS("./testdata/invalid_cert.p12", "password")
}

View File

@@ -8,10 +8,10 @@ import (
// SignatureOptions 微信服务器验证参数
type SignatureOptions struct {
Signature string `form:"msg_signature"`
TimeStamp string `form:"timestamp"`
Nonce string `form:"nonce"`
EchoStr string `form:"echostr"`
Signature string `form:"msg_signature" json:"msg_signature"`
TimeStamp string `form:"timestamp" json:"timestamp"`
Nonce string `form:"nonce" json:"nonce"`
EchoStr string `form:"echostr" json:"echostr"`
}
// VerifyURL 验证请求参数是否合法并返回解密后的消息内容

View File

@@ -191,12 +191,6 @@ func (r *Client) GetTempFile(mediaID string) ([]byte, error) {
return nil, err
}
// 检查响应是否为错误信息
err = util.DecodeWithCommonError(response, "GetTempFile")
if err != nil {
return nil, err
}
// 如果不是错误响应,则返回原始数据
return response, nil
// 检查响应是否为错误信息,如果不是错误响应,则返回原始数据
return util.HandleFileResponse(response, "GetTempFile")
}