Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<p align="center"><strong>Simple Go HTTP client with Black Magic</strong></p>
<p align="center">
<a href="https://github.com/imroc/req/actions/workflows/ci.yml?query=branch%3Amaster"><img src="https://github.com/imroc/req/actions/workflows/ci.yml/badge.svg" alt="Build Status"></a>
<a href="https://goreportcard.com/report/github.com/imroc/req/v3"><img src="https://goreportcard.com/badge/github.com/imroc/req/v3" alt="Go Report Card"></a>
<a href="https://pkg.go.dev/github.com/imroc/req/v3"><img src="https://pkg.go.dev/badge/github.com/imroc/req/v3.svg"></a>
<a href="https://goreportcard.com/report/github.com/0xobjc/req/v3"><img src="https://goreportcard.com/badge/github.com/0xobjc/req/v3" alt="Go Report Card"></a>
<a href="https://pkg.go.dev/github.com/0xobjc/req/v3"><img src="https://pkg.go.dev/badge/github.com/0xobjc/req/v3.svg"></a>
<a href="LICENSE"><img src="https://img.shields.io/github/license/imroc/req.svg" alt="License"></a>
<a href="https://github.com/imroc/req/releases"><img src="https://img.shields.io/github/v/release/imroc/req?display_name=tag&sort=semver" alt="GitHub Releases"></a>
<a href="https://github.com/avelino/awesome-go"><img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Go"></a>
Expand Down Expand Up @@ -38,15 +38,15 @@ Full documentation is available on the official website: https://req.cool.
You first need [Go](https://go.dev/) installed (version 1.24+ is required), then you can use the below Go command to install req:

``` sh
go get github.com/imroc/req/v3
go get github.com/0xobjc/req/v3
```

**Import**

Import req to your code:

```go
import "github.com/imroc/req/v3"
import "github.com/0xobjc/req/v3"
```

**Basic Usage**
Expand All @@ -60,7 +60,7 @@ $ cat main.go
package main

import (
"github.com/imroc/req/v3"
"github.com/0xobjc/req/v3"
)

func main() {
Expand All @@ -79,7 +79,7 @@ $ go run main.go
:method: GET
:path: /uuid
:scheme: https
user-agent: req/v3 (https://github.com/imroc/req/v3)
user-agent: req/v3 (https://github.com/0xobjc/req/v3)
accept-encoding: gzip

:status: 200
Expand All @@ -97,7 +97,7 @@ access-control-allow-credentials: true
2022/05/19 10:05:09.340974 DEBUG [req] HTTP/1.1 GET https://httpbin.org/uuid
GET /uuid HTTP/1.1
Host: httpbin.org
User-Agent: req/v3 (https://github.com/imroc/req/v3)
User-Agent: req/v3 (https://github.com/0xobjc/req/v3)
Accept-Encoding: gzip

HTTP/1.1 200 OK
Expand Down Expand Up @@ -136,7 +136,7 @@ package main

import (
"fmt"
"github.com/imroc/req/v3"
"github.com/0xobjc/req/v3"
"log"
)

Expand Down Expand Up @@ -164,7 +164,7 @@ package main

import (
"fmt"
"github.com/imroc/req/v3"
"github.com/0xobjc/req/v3"
"log"
"time"
)
Expand Down Expand Up @@ -232,7 +232,7 @@ package main

import (
"fmt"
"github.com/imroc/req/v3"
"github.com/0xobjc/req/v3"
"log"
"time"
)
Expand Down Expand Up @@ -296,7 +296,7 @@ package main

import (
"fmt"
"github.com/imroc/req/v3"
"github.com/0xobjc/req/v3"
"log"
)

Expand Down Expand Up @@ -337,7 +337,7 @@ func main() {
:method: POST
:path: /post
:scheme: https
user-agent: req/v3 (https://github.com/imroc/req/v3)
user-agent: req/v3 (https://github.com/0xobjc/req/v3)
content-type: application/json; charset=utf-8
content-length: 55
accept-encoding: gzip
Expand All @@ -362,7 +362,7 @@ access-control-allow-credentials: true
"Content-Length": "55",
"Content-Type": "application/json; charset=utf-8",
"Host": "httpbin.org",
"User-Agent": "req/v3 (https://github.com/imroc/req/v3)",
"User-Agent": "req/v3 (https://github.com/0xobjc/req/v3)",
"X-Amzn-Trace-Id": "Root=1-628633d4-7559d633152b4307288ead2e"
},
"json": {
Expand All @@ -387,7 +387,7 @@ package main

import (
"fmt"
"github.com/imroc/req/v3"
"github.com/0xobjc/req/v3"
)

type APIResponse struct {
Expand Down Expand Up @@ -425,7 +425,7 @@ Here is an example of building GitHub's SDK with req, using two styles (`GetUser
import (
"context"
"fmt"
"github.com/imroc/req/v3"
"github.com/0xobjc/req/v3"
)

type ErrorMessage struct {
Expand Down
17 changes: 14 additions & 3 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import (
utls "github.com/refraction-networking/utls"
"golang.org/x/net/publicsuffix"

"github.com/imroc/req/v3/http2"
"github.com/imroc/req/v3/internal/header"
"github.com/imroc/req/v3/internal/util"
"github.com/0xobjc/req/v3/http2"
"github.com/0xobjc/req/v3/internal/header"
"github.com/0xobjc/req/v3/internal/util"
)

// DefaultClient returns the global default Client.
Expand Down Expand Up @@ -73,6 +73,7 @@ type Client struct {
responseBodyTransformer func(rawBody []byte, req *Request, resp *Response) (transformedBody []byte, err error)
resultStateCheckFunc func(resp *Response) ResultState
onError ErrorHook
ctx *clientContext // 使Client拥有携带上下文信息的能力
}

type ErrorHook func(client *Client, req *Request, resp *Response, err error)
Expand All @@ -82,6 +83,7 @@ func (c *Client) R() *Request {
return &Request{
client: c,
retryOption: c.retryOption.Clone(),
ctx: c.Context(), // 继承 Client 的上下文
}
}

Expand Down Expand Up @@ -1527,6 +1529,12 @@ func (c *Client) Clone() *Client {
cc.afterResponse = cloneSlice(c.afterResponse)
cc.dumpOptions = c.dumpOptions.Clone()
cc.retryOption = c.retryOption.Clone()

// clone context and clientContext
cc.ctx = &clientContext{
context: c.ctx.context,
}

return &cc
}

Expand Down Expand Up @@ -1565,6 +1573,9 @@ func C() *Client {
xmlMarshal: xml.Marshal,
xmlUnmarshal: xml.Unmarshal,
cookiejarFactory: memoryCookieJarFactory,
ctx: &clientContext{
context: context.Background(),
},
}
c.SetRedirectPolicy(DefaultRedirectPolicy())
c.initCookieJar()
Expand Down
2 changes: 1 addition & 1 deletion client_impersonate.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"strconv"
"strings"

"github.com/imroc/req/v3/http2"
"github.com/0xobjc/req/v3/http2"
utls "github.com/refraction-networking/utls"
)

Expand Down
4 changes: 2 additions & 2 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import (
"testing"
"time"

"github.com/imroc/req/v3/internal/header"
"github.com/imroc/req/v3/internal/tests"
"github.com/0xobjc/req/v3/internal/header"
"github.com/0xobjc/req/v3/internal/tests"
"golang.org/x/net/publicsuffix"
)

Expand Down
2 changes: 1 addition & 1 deletion client_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"net/url"
"time"

"github.com/imroc/req/v3/http2"
"github.com/0xobjc/req/v3/http2"
utls "github.com/refraction-networking/utls"
)

Expand Down
78 changes: 78 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package req

import (
"context"
"sync"
)

// clientContext 为 Client 提供上下文能力,确保并发安全
type clientContext struct {
mu sync.RWMutex
context context.Context
}

// WithContext 添加上下文键值对,使用读写锁保证并发安全
// 这种方式避免了 Clone 整个 Client 的开销
func (c *Client) WithContext(key, value any) *Client {
if c.ctx == nil {
c.ctx = &clientContext{
context: context.Background(),
}
}

c.ctx.mu.Lock()
defer c.ctx.mu.Unlock()

if c.ctx.context == nil {
c.ctx.context = context.Background()
}
c.ctx.context = context.WithValue(c.ctx.context, key, value)
return c
}

// GetContext 获取上下文值,使用读锁保证并发安全
func (c *Client) GetContext(key any) any {
if c.ctx == nil {
return context.Background().Value(key)
}

c.ctx.mu.RLock()
defer c.ctx.mu.RUnlock()

if c.ctx.context == nil {
return nil
}
return c.ctx.context.Value(key)
}

// SetContext 设置基础上下文,使用写锁保证并发安全
func (c *Client) SetContext(ctx context.Context) *Client {
if ctx == nil {
ctx = context.Background()
}

if c.ctx == nil {
c.ctx = &clientContext{}
}

c.ctx.mu.Lock()
defer c.ctx.mu.Unlock()

c.ctx.context = ctx
return c
}

// Context 获取当前上下文,使用读锁保证并发安全
func (c *Client) Context() context.Context {
if c.ctx == nil {
return context.Background()
}

c.ctx.mu.RLock()
defer c.ctx.mu.RUnlock()

if c.ctx.context == nil {
return context.Background()
}
return c.ctx.context
}
2 changes: 1 addition & 1 deletion decode.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package req

import (
"github.com/imroc/req/v3/internal/charsets"
"github.com/0xobjc/req/v3/internal/charsets"
"io"
"strings"
)
Expand Down
2 changes: 1 addition & 1 deletion decode_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package req

import (
"github.com/imroc/req/v3/internal/tests"
"github.com/0xobjc/req/v3/internal/tests"
"testing"
)

Expand Down
2 changes: 1 addition & 1 deletion digest.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"net/http"
"sync"

"github.com/0xobjc/req/v3/internal/header"
"github.com/icholy/digest"
"github.com/imroc/req/v3/internal/header"
)

// cchal is a cached challenge and the number of times it's been used.
Expand Down
2 changes: 1 addition & 1 deletion dump.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package req

import (
"github.com/imroc/req/v3/internal/dump"
"github.com/0xobjc/req/v3/internal/dump"
"io"
"os"
)
Expand Down
20 changes: 10 additions & 10 deletions examples/find-popular-repo/go.mod
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
module find-popular-repo

go 1.22.0
go 1.24

toolchain go1.22.3
toolchain go1.24.3

replace github.com/imroc/req/v3 => ../../
replace github.com/0xobjc/req/v3 => ../../

require github.com/imroc/req/v3 v3.0.0
require github.com/0xobjc/req/v3 v3.0.0

require (
github.com/cheekybits/genny v1.0.0 // indirect
Expand All @@ -21,11 +21,11 @@ require (
github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.20.0 // indirect
golang.org/x/tools v0.27.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/tools v0.34.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
)
Loading