Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fa1a8af683 | |||
| 501f479a87 | |||
| 60979b12eb | |||
| 62bce65656 | |||
|
|
55623618a5 | ||
| 6209a03044 | |||
|
|
9bb2f8cffa | ||
| 24801750a7 | |||
|
|
b37fca95cf | ||
| 4c4a024e19 | |||
| b93e634873 | |||
| 4a6414b2b8 | |||
| 938ddd2ab3 | |||
| 04e0597b73 | |||
| 4d55c7b90a | |||
| fbe82a3905 | |||
|
|
14490a419e | ||
| d434261168 | |||
| 2e384a5b75 | |||
| d9e7ac75ef |
28
.github/autoapprove.yml
vendored
Normal file
28
.github/autoapprove.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
name: "autoapprove"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types: [assigned, opened, synchronize, reopened]
|
||||||
|
workflow_run:
|
||||||
|
workflows: ["prbuild"]
|
||||||
|
types:
|
||||||
|
- completed
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
autoapprove:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: approve
|
||||||
|
run: [ "curl -o tea https://dl.gitea.com/tea/main/tea-main-linux-amd64",
|
||||||
|
"chmod +x ./tea",
|
||||||
|
"./tea login add --name unistack --token ${{ secrets.GITHUB_TOKEN }} --url https://git.unistack.org",
|
||||||
|
"./tea pr --repo ${{ github.event.repository.name }}"
|
||||||
|
]
|
||||||
|
if: github.actor == 'vtolstov'
|
||||||
|
id: approve
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
94
.github/workflows/job_sync.yml
vendored
Normal file
94
.github/workflows/job_sync.yml
vendored
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
name: sync
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '*/5 * * * *'
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync:
|
||||||
|
if: github.server_url != 'https://github.com'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: init
|
||||||
|
run: |
|
||||||
|
git config --global user.email "vtolstov <vtolstov@users.noreply.github.com>"
|
||||||
|
git config --global user.name "github-actions[bot]"
|
||||||
|
echo "machine git.unistack.org login vtolstov password ${{ secrets.TOKEN_GITEA }}" >> /root/.netrc
|
||||||
|
echo "machine github.com login vtolstov password ${{ secrets.TOKEN_GITHUB }}" >> /root/.netrc
|
||||||
|
|
||||||
|
- name: check master
|
||||||
|
id: check_master
|
||||||
|
run: |
|
||||||
|
src_hash=$(git ls-remote https://github.com/${GITHUB_REPOSITORY} refs/heads/master | cut -f1)
|
||||||
|
dst_hash=$(git ls-remote ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} refs/heads/master | cut -f1)
|
||||||
|
echo "src_hash=$src_hash"
|
||||||
|
echo "dst_hash=$dst_hash"
|
||||||
|
if [ "$src_hash" != "$dst_hash" ]; then
|
||||||
|
echo "sync_needed=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "sync_needed=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: sync master
|
||||||
|
if: steps.check_master.outputs.sync_needed == 'true'
|
||||||
|
run: |
|
||||||
|
git clone --filter=blob:none --filter=tree:0 --branch master --single-branch ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} repo
|
||||||
|
cd repo
|
||||||
|
git remote add --no-tags --fetch --track master upstream https://github.com/${GITHUB_REPOSITORY}
|
||||||
|
git pull --rebase upstream master
|
||||||
|
git push upstream master --progress
|
||||||
|
git push origin master --progress
|
||||||
|
cd ../
|
||||||
|
rm -rf repo
|
||||||
|
|
||||||
|
- name: check v3
|
||||||
|
id: check_v3
|
||||||
|
run: |
|
||||||
|
src_hash=$(git ls-remote https://github.com/${GITHUB_REPOSITORY} refs/heads/v3 | cut -f1)
|
||||||
|
dst_hash=$(git ls-remote ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} refs/heads/v3 | cut -f1)
|
||||||
|
echo "src_hash=$src_hash"
|
||||||
|
echo "dst_hash=$dst_hash"
|
||||||
|
if [ "$src_hash" != "$dst_hash" ]; then
|
||||||
|
echo "sync_needed=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "sync_needed=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: sync v3
|
||||||
|
if: steps.check_v3.outputs.sync_needed == 'true'
|
||||||
|
run: |
|
||||||
|
git clone --filter=blob:none --filter=tree:0 --branch v3 --single-branch ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} repo
|
||||||
|
cd repo
|
||||||
|
git remote add --no-tags --fetch --track v3 upstream https://github.com/${GITHUB_REPOSITORY}
|
||||||
|
git pull --rebase upstream v3
|
||||||
|
git push upstream v3 --progress
|
||||||
|
git push origin v3 --progress
|
||||||
|
cd ../
|
||||||
|
rm -rf repo
|
||||||
|
|
||||||
|
- name: check v4
|
||||||
|
id: check_v4
|
||||||
|
run: |
|
||||||
|
src_hash=$(git ls-remote https://github.com/${GITHUB_REPOSITORY} refs/heads/v4 | cut -f1)
|
||||||
|
dst_hash=$(git ls-remote ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} refs/heads/v4 | cut -f1)
|
||||||
|
echo "src_hash=$src_hash"
|
||||||
|
echo "dst_hash=$dst_hash"
|
||||||
|
if [ "$src_hash" != "$dst_hash" ]; then
|
||||||
|
echo "sync_needed=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "sync_needed=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: sync v4
|
||||||
|
if: steps.check_v4.outputs.sync_needed == 'true'
|
||||||
|
run: |
|
||||||
|
git clone --filter=blob:none --filter=tree:0 --branch v4 --single-branch ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} repo
|
||||||
|
cd repo
|
||||||
|
git remote add --no-tags --fetch --track v4 upstream https://github.com/${GITHUB_REPOSITORY}
|
||||||
|
git pull --rebase upstream v4
|
||||||
|
git push upstream v4 --progress
|
||||||
|
git push origin v4 --progress
|
||||||
|
cd ../
|
||||||
|
rm -rf repo
|
||||||
36
README.md
36
README.md
@@ -1,8 +1,8 @@
|
|||||||
# HTTP Client
|
# HTTP Client
|
||||||

|

|
||||||
|
|
||||||
This plugin is an HTTP client for [Micro](https://pkg.go.dev/go.unistack.org/micro/v3).
|
This plugin is an HTTP client for [Micro](https://pkg.go.dev/go.unistack.org/micro/v4).
|
||||||
It implements the [micro.Client](https://pkg.go.dev/go.unistack.org/micro/v3/client#Client) interface.
|
It implements the [micro.Client](https://pkg.go.dev/go.unistack.org/micro/v4/client#Client) interface.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
@@ -18,8 +18,8 @@ implements HTTP rules defined in the [google/api/http.proto](https://github.com/
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3"
|
"go.unistack.org/micro/v4"
|
||||||
http "go.unistack.org/micro-client-http/v3"
|
http "go.unistack.org/micro-client-http/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
service := micro.NewService(
|
service := micro.NewService(
|
||||||
@@ -32,9 +32,9 @@ service := micro.NewService(
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
http "go.unistack.org/micro-client-http/v3"
|
http "go.unistack.org/micro-client-http/v4"
|
||||||
jsoncodec "go.unistack.org/micro-codec-json/v3"
|
jsoncodec "go.unistack.org/micro-codec-json/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
c := http.NewClient(
|
c := http.NewClient(
|
||||||
@@ -60,8 +60,8 @@ err := c.Call(
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
http "go.unistack.org/micro-client-http/v3"
|
http "go.unistack.org/micro-client-http/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
err := c.Call(
|
err := c.Call(
|
||||||
@@ -79,8 +79,8 @@ err := c.Call(
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
http "go.unistack.org/micro-client-http/v3"
|
http "go.unistack.org/micro-client-http/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx := metadata.NewOutgoingContext(ctx, metadata.Pairs(
|
ctx := metadata.NewOutgoingContext(ctx, metadata.Pairs(
|
||||||
@@ -100,8 +100,8 @@ err := c.Call(
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
http "go.unistack.org/micro-client-http/v3"
|
http "go.unistack.org/micro-client-http/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
respMetadata := metadata.Metadata{}
|
respMetadata := metadata.Metadata{}
|
||||||
@@ -118,8 +118,8 @@ err := c.Call(
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
http "go.unistack.org/micro-client-http/v3"
|
http "go.unistack.org/micro-client-http/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(
|
ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(
|
||||||
@@ -138,9 +138,9 @@ err := c.Call(
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
http "go.unistack.org/micro-client-http/v3"
|
http "go.unistack.org/micro-client-http/v4"
|
||||||
status "go.unistack.org/micro-client-http/v3/status"
|
status "go.unistack.org/micro-client-http/v4/status"
|
||||||
jsoncodec "go.unistack.org/micro-codec-json/v3"
|
jsoncodec "go.unistack.org/micro-codec-json/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
err := c.Call(
|
err := c.Call(
|
||||||
|
|||||||
@@ -3745,7 +3745,7 @@ const file_test_messages_proto_rawDesc = "" +
|
|||||||
"\fSpecialError\x12\x12\n" +
|
"\fSpecialError\x12\x12\n" +
|
||||||
"\x04code\x18\x01 \x01(\tR\x04code\x12\x10\n" +
|
"\x04code\x18\x01 \x01(\tR\x04code\x12\x10\n" +
|
||||||
"\x03msg\x18\x02 \x01(\tR\x03msg\x12\x18\n" +
|
"\x03msg\x18\x02 \x01(\tR\x03msg\x12\x18\n" +
|
||||||
"\awarning\x18\x03 \x01(\tR\awarningB2Z0go.unistack.org/micro-client-http/v3/proto;protob\x06proto3"
|
"\awarning\x18\x03 \x01(\tR\awarningB2Z0go.unistack.org/micro-client-http/v4/proto;protob\x06proto3"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_test_messages_proto_rawDescOnce sync.Once
|
file_test_messages_proto_rawDescOnce sync.Once
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ syntax = "proto3";
|
|||||||
|
|
||||||
package proto;
|
package proto;
|
||||||
|
|
||||||
option go_package = "go.unistack.org/micro-client-http/v3/proto;proto";
|
option go_package = "go.unistack.org/micro-client-http/v4/proto;proto";
|
||||||
|
|
||||||
message TestRequestBuilder {}
|
message TestRequestBuilder {}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
pb "go.unistack.org/micro-client-http/v3/builder/proto"
|
pb "go.unistack.org/micro-client-http/v4/builder/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// sink prevents the compiler from optimizing away parsePathTemplate results.
|
// sink prevents the compiler from optimizing away parsePathTemplate results.
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
"go.unistack.org/micro-client-http/v3/builder"
|
"go.unistack.org/micro-client-http/v4/builder"
|
||||||
pb "go.unistack.org/micro-client-http/v3/builder/proto"
|
pb "go.unistack.org/micro-client-http/v4/builder/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewRequestBuilder(t *testing.T) {
|
func TestNewRequestBuilder(t *testing.T) {
|
||||||
|
|||||||
44
client.go
44
client.go
@@ -7,13 +7,17 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/errors"
|
"go.unistack.org/micro/v4/errors"
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
"go.unistack.org/micro/v3/semconv"
|
"go.unistack.org/micro/v4/semconv"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
|
|
||||||
|
"go.unistack.org/micro-client-http/v4/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ client.Client = (*Client)(nil)
|
||||||
|
|
||||||
var DefaultContentType = "application/json"
|
var DefaultContentType = "application/json"
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
@@ -91,25 +95,45 @@ func (c *Client) NewRequest(service, method string, req any, opts ...client.Requ
|
|||||||
func (c *Client) Call(ctx context.Context, req client.Request, rsp any, opts ...client.CallOption) error {
|
func (c *Client) Call(ctx context.Context, req client.Request, rsp any, opts ...client.CallOption) error {
|
||||||
ts := time.Now()
|
ts := time.Now()
|
||||||
c.opts.Meter.Counter(semconv.ClientRequestInflight, "endpoint", req.Endpoint()).Inc()
|
c.opts.Meter.Counter(semconv.ClientRequestInflight, "endpoint", req.Endpoint()).Inc()
|
||||||
|
|
||||||
var sp tracer.Span
|
var sp tracer.Span
|
||||||
ctx, sp = c.opts.Tracer.Start(ctx, req.Endpoint()+" rpc-client",
|
ctx, sp = c.opts.Tracer.Start(ctx, req.Endpoint()+" rpc-client",
|
||||||
tracer.WithSpanKind(tracer.SpanKindClient),
|
tracer.WithSpanKind(tracer.SpanKindClient),
|
||||||
tracer.WithSpanLabels("endpoint", req.Endpoint()),
|
tracer.WithSpanLabels("endpoint", req.Endpoint()),
|
||||||
)
|
)
|
||||||
|
defer sp.Finish()
|
||||||
|
|
||||||
err := c.funcCall(ctx, req, rsp, opts...)
|
err := c.funcCall(ctx, req, rsp, opts...)
|
||||||
|
|
||||||
c.opts.Meter.Counter(semconv.ClientRequestInflight, "endpoint", req.Endpoint()).Dec()
|
c.opts.Meter.Counter(semconv.ClientRequestInflight, "endpoint", req.Endpoint()).Dec()
|
||||||
te := time.Since(ts)
|
te := time.Since(ts)
|
||||||
c.opts.Meter.Summary(semconv.ClientRequestLatencyMicroseconds, "endpoint", req.Endpoint()).Update(te.Seconds())
|
c.opts.Meter.Summary(semconv.ClientRequestLatencyMicroseconds, "endpoint", req.Endpoint()).Update(te.Seconds())
|
||||||
c.opts.Meter.Histogram(semconv.ClientRequestDurationSeconds, "endpoint", req.Endpoint()).Update(te.Seconds())
|
c.opts.Meter.Histogram(semconv.ClientRequestDurationSeconds, "endpoint", req.Endpoint()).Update(te.Seconds())
|
||||||
|
|
||||||
if me := errors.FromError(err); me == nil {
|
var (
|
||||||
sp.Finish()
|
statusCode int
|
||||||
c.opts.Meter.Counter(semconv.ClientRequestTotal, "endpoint", req.Endpoint(), "status", "success", "code", strconv.Itoa(int(200))).Inc()
|
statusLabel string
|
||||||
} else {
|
)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
statusCode = http.StatusOK
|
||||||
|
statusLabel = "success"
|
||||||
|
} else if st, ok := status.FromError(err); ok {
|
||||||
|
statusCode = st.Code()
|
||||||
|
statusLabel = "failure"
|
||||||
|
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||||
|
} else if me := errors.FromError(err); me != nil {
|
||||||
|
statusCode = int(me.Code)
|
||||||
|
statusLabel = "failure"
|
||||||
|
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||||
|
} else {
|
||||||
|
statusCode = http.StatusInternalServerError
|
||||||
|
statusLabel = "failure"
|
||||||
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||||
c.opts.Meter.Counter(semconv.ClientRequestTotal, "endpoint", req.Endpoint(), "status", "failure", "code", strconv.Itoa(int(me.Code))).Inc()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.opts.Meter.Counter(semconv.ClientRequestTotal, "endpoint", req.Endpoint(), "status", statusLabel, "code", strconv.Itoa(statusCode)).Inc()
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"google.golang.org/protobuf/reflect/protoreflect"
|
"google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
|
||||||
"go.unistack.org/micro-client-http/v3/builder"
|
"go.unistack.org/micro-client-http/v4/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildHTTPRequest(
|
func buildHTTPRequest(
|
||||||
@@ -119,10 +119,23 @@ func buildHTTPRequest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if log.V(logger.DebugLevel) {
|
if log.V(logger.DebugLevel) {
|
||||||
log.Debug(
|
if shouldLogBody(ct) {
|
||||||
ctx,
|
log.Debug(
|
||||||
fmt.Sprintf("request %s to %s with headers %v body %s", method, u.String(), hreq.Header, body),
|
ctx,
|
||||||
)
|
fmt.Sprintf(
|
||||||
|
"micro.client http request: method=%s url=%s headers=%v body=%s",
|
||||||
|
method, u.String(), hreq.Header, body,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
log.Debug(
|
||||||
|
ctx,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"micro.client http request: method=%s url=%s headers=%v",
|
||||||
|
method, u.String(), hreq.Header,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hreq, nil
|
return hreq, nil
|
||||||
@@ -205,7 +218,7 @@ func setHeadersAndCookies(ctx context.Context, r *http.Request, ct string, opts
|
|||||||
applyCookies(r, v)
|
applyCookies(r, v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r.Header[k] = append(r.Header[k], v)
|
r.Header[k] = append(r.Header[k], v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,18 +228,20 @@ func setHeadersAndCookies(ctx context.Context, r *http.Request, ct string, opts
|
|||||||
applyCookies(r, v)
|
applyCookies(r, v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r.Header[k] = append(r.Header[k], v)
|
r.Header[k] = append(r.Header[k], v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyCookies(r *http.Request, rawCookies string) {
|
func applyCookies(r *http.Request, rawCookies []string) {
|
||||||
if len(rawCookies) == 0 {
|
if len(rawCookies) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp := http.Request{Header: http.Header{}}
|
tmp := http.Request{Header: http.Header{}}
|
||||||
tmp.Header.Set("Cookie", rawCookies)
|
for _, raw := range rawCookies {
|
||||||
|
tmp.Header.Add("Cookie", raw)
|
||||||
|
}
|
||||||
|
|
||||||
for _, c := range tmp.Cookies() {
|
for _, c := range tmp.Cookies() {
|
||||||
r.AddCookie(c)
|
r.AddCookie(c)
|
||||||
@@ -259,3 +274,18 @@ func validateHeadersAndCookies(r *http.Request, parameters map[string]map[string
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func shouldLogBody(contentType string) bool {
|
||||||
|
ct := strings.ToLower(strings.Split(contentType, ";")[0])
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(ct, "text/"): // => text/html, text/plain, text/csv etc.
|
||||||
|
return true
|
||||||
|
case ct == "application/json",
|
||||||
|
ct == "application/xml",
|
||||||
|
ct == "application/x-www-form-urlencoded",
|
||||||
|
ct == "application/yaml":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
jsoncodec "go.unistack.org/micro-codec-json/v3"
|
jsoncodec "go.unistack.org/micro-codec-json/v4"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
pb "go.unistack.org/micro-client-http/v3/builder/proto"
|
pb "go.unistack.org/micro-client-http/v4/builder/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestJoinURL(t *testing.T) {
|
func TestJoinURL(t *testing.T) {
|
||||||
@@ -232,24 +232,24 @@ func TestMarshallMsg(t *testing.T) {
|
|||||||
func TestApplyCookies(t *testing.T) {
|
func TestApplyCookies(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
rawCookies string
|
rawCookies []string
|
||||||
want []*http.Cookie
|
want []*http.Cookie
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty",
|
name: "empty",
|
||||||
rawCookies: "",
|
rawCookies: []string{},
|
||||||
want: []*http.Cookie{},
|
want: []*http.Cookie{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "single cookie",
|
name: "single cookie",
|
||||||
rawCookies: "session=abc123",
|
rawCookies: []string{"session=abc123"},
|
||||||
want: []*http.Cookie{
|
want: []*http.Cookie{
|
||||||
{Name: "session", Value: "abc123"},
|
{Name: "session", Value: "abc123"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple cookies separate items",
|
name: "multiple cookies separate items",
|
||||||
rawCookies: "session=abc123; user=john",
|
rawCookies: []string{"session=abc123", "user=john"},
|
||||||
want: []*http.Cookie{
|
want: []*http.Cookie{
|
||||||
{Name: "session", Value: "abc123"},
|
{Name: "session", Value: "abc123"},
|
||||||
{Name: "user", Value: "john"},
|
{Name: "user", Value: "john"},
|
||||||
@@ -257,7 +257,7 @@ func TestApplyCookies(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple cookies in one item",
|
name: "multiple cookies in one item",
|
||||||
rawCookies: "a=1; b=2",
|
rawCookies: []string{"a=1; b=2"},
|
||||||
want: []*http.Cookie{
|
want: []*http.Cookie{
|
||||||
{Name: "a", Value: "1"},
|
{Name: "a", Value: "1"},
|
||||||
{Name: "b", Value: "2"},
|
{Name: "b", Value: "2"},
|
||||||
@@ -265,7 +265,7 @@ func TestApplyCookies(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "mix of combined and separate cookies",
|
name: "mix of combined and separate cookies",
|
||||||
rawCookies: "a=1; b=2; c=3",
|
rawCookies: []string{"a=1; b=2", "c=3"},
|
||||||
want: []*http.Cookie{
|
want: []*http.Cookie{
|
||||||
{Name: "a", Value: "1"},
|
{Name: "a", Value: "1"},
|
||||||
{Name: "b", Value: "2"},
|
{Name: "b", Value: "2"},
|
||||||
@@ -274,7 +274,7 @@ func TestApplyCookies(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "duplicate cookies",
|
name: "duplicate cookies",
|
||||||
rawCookies: "session=abc123; session=xyz",
|
rawCookies: []string{"session=abc123", "session=xyz"},
|
||||||
want: []*http.Cookie{
|
want: []*http.Cookie{
|
||||||
{Name: "session", Value: "abc123"},
|
{Name: "session", Value: "abc123"},
|
||||||
{Name: "session", Value: "xyz"},
|
{Name: "session", Value: "xyz"},
|
||||||
@@ -282,7 +282,7 @@ func TestApplyCookies(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "cookie with spaces",
|
name: "cookie with spaces",
|
||||||
rawCookies: "token=abc 123",
|
rawCookies: []string{"token=abc 123"},
|
||||||
want: []*http.Cookie{
|
want: []*http.Cookie{
|
||||||
{Name: "token", Value: "abc 123", Quoted: true},
|
{Name: "token", Value: "abc 123", Quoted: true},
|
||||||
},
|
},
|
||||||
@@ -399,3 +399,49 @@ func TestValidateHeadersAndCookies(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShouldLogBody(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
contentType string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
// --- text/*
|
||||||
|
{"plain text", "text/plain", true},
|
||||||
|
{"html", "text/html", true},
|
||||||
|
{"csv", "text/csv", true},
|
||||||
|
{"yaml text", "text/yaml", true},
|
||||||
|
|
||||||
|
// --- application/*
|
||||||
|
{"json", "application/json", true},
|
||||||
|
{"xml", "application/xml", true},
|
||||||
|
{"form-urlencoded", "application/x-www-form-urlencoded", true},
|
||||||
|
{"yaml", "application/yaml", true},
|
||||||
|
|
||||||
|
// --- with parameters
|
||||||
|
{"json with charset", "application/json; charset=utf-8", true},
|
||||||
|
{"binary with charset", "application/octet-stream; charset=utf-8", false},
|
||||||
|
|
||||||
|
// --- binary
|
||||||
|
{"multipart form", "multipart/form-data", false},
|
||||||
|
{"binary stream", "application/octet-stream", false},
|
||||||
|
{"pdf", "application/pdf", false},
|
||||||
|
{"protobuf", "application/protobuf", false},
|
||||||
|
{"image", "image/png", false},
|
||||||
|
|
||||||
|
// --- edge cases
|
||||||
|
{"upper case type", "APPLICATION/JSON", true},
|
||||||
|
{"mixed case type", "Text/HTML", true},
|
||||||
|
{"unknown text prefix", "TEXT/FOO", true},
|
||||||
|
{"weird semicolon only", ";", false},
|
||||||
|
{"spaces only", " ", false},
|
||||||
|
{"empty content-type", "", false},
|
||||||
|
{"missing main type", "/plain", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
require.Equal(t, tt.want, shouldLogBody(tt.contentType))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package http
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Add stream support in the future.
|
// TODO: Add stream support in the future.
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/errors"
|
"go.unistack.org/micro/v4/errors"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/selector"
|
"go.unistack.org/micro/v4/selector"
|
||||||
|
|
||||||
"go.unistack.org/micro-client-http/v3/status"
|
"go.unistack.org/micro-client-http/v4/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Client) fnCall(ctx context.Context, req client.Request, rsp any, opts ...client.CallOption) error {
|
func (c *Client) fnCall(ctx context.Context, req client.Request, rsp any, opts ...client.CallOption) error {
|
||||||
@@ -207,11 +207,9 @@ func (c *Client) parseRsp(ctx context.Context, hrsp *http.Response, rsp any, opt
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf []byte
|
|
||||||
|
|
||||||
if opts.ResponseMetadata != nil {
|
if opts.ResponseMetadata != nil {
|
||||||
for k, v := range hrsp.Header {
|
for k, v := range hrsp.Header {
|
||||||
opts.ResponseMetadata.Set(k, strings.Join(v, ","))
|
opts.ResponseMetadata.Append(k, v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +222,8 @@ func (c *Client) parseRsp(ctx context.Context, hrsp *http.Response, rsp any, opt
|
|||||||
ct = htype
|
ct = htype
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var buf []byte
|
||||||
|
|
||||||
if hrsp.Body != nil {
|
if hrsp.Body != nil {
|
||||||
var err error
|
var err error
|
||||||
buf, err = io.ReadAll(hrsp.Body)
|
buf, err = io.ReadAll(hrsp.Body)
|
||||||
@@ -232,15 +232,31 @@ func (c *Client) parseRsp(ctx context.Context, hrsp *http.Response, rsp any, opt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if log.V(logger.DebugLevel) {
|
||||||
|
if shouldLogBody(ct) {
|
||||||
|
log.Debug(
|
||||||
|
ctx,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"micro.client http response: status=%s headers=%v body=%s",
|
||||||
|
hrsp.Status, hrsp.Header, buf,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
log.Debug(
|
||||||
|
ctx,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"micro.client http response: status=%s headers=%v",
|
||||||
|
hrsp.Status, hrsp.Header,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cf, err := c.newCodec(ct)
|
cf, err := c.newCodec(ct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.InternalServerError("go.micro.client", "unknown content-type %s: %v", ct, err)
|
return errors.InternalServerError("go.micro.client", "unknown content-type %s: %v", ct, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if log.V(logger.DebugLevel) {
|
|
||||||
log.Debug(ctx, fmt.Sprintf("response with headers: %v and body: %s", hrsp.Header, buf))
|
|
||||||
}
|
|
||||||
|
|
||||||
if hrsp.StatusCode < http.StatusBadRequest {
|
if hrsp.StatusCode < http.StatusBadRequest {
|
||||||
if err = cf.Unmarshal(buf, rsp); err != nil {
|
if err = cf.Unmarshal(buf, rsp); err != nil {
|
||||||
return errors.InternalServerError("go.micro.client", "unmarshal response: %v", err)
|
return errors.InternalServerError("go.micro.client", "unmarshal response: %v", err)
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
jsoncodec "go.unistack.org/micro-codec-json/v3"
|
jsoncodec "go.unistack.org/micro-codec-json/v4"
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
microerr "go.unistack.org/micro/v3/errors"
|
microerr "go.unistack.org/micro/v4/errors"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
httpcli "go.unistack.org/micro-client-http/v3"
|
httpcli "go.unistack.org/micro-client-http/v4"
|
||||||
pb "go.unistack.org/micro-client-http/v3/builder/proto"
|
pb "go.unistack.org/micro-client-http/v4/builder/proto"
|
||||||
"go.unistack.org/micro-client-http/v3/status"
|
"go.unistack.org/micro-client-http/v4/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestClient_Call_Get(t *testing.T) {
|
func TestClient_Call_Get(t *testing.T) {
|
||||||
@@ -130,10 +130,9 @@ func TestClient_Call_Get(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
md, _ = metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value")
|
ctx = metadata.NewOutgoingContext(
|
||||||
ctx = metadata.NewOutgoingContext(
|
|
||||||
context.Background(),
|
context.Background(),
|
||||||
md,
|
metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value"),
|
||||||
)
|
)
|
||||||
rsp = &response{}
|
rsp = &response{}
|
||||||
respMetadata = metadata.Metadata{}
|
respMetadata = metadata.Metadata{}
|
||||||
@@ -163,8 +162,8 @@ func TestClient_Call_Get(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, proto.Equal(tt.wantRsp, rsp))
|
require.True(t, proto.Equal(tt.wantRsp, rsp))
|
||||||
require.Equal(t, "application/json", respMetadata.MustGet("Content-Type"))
|
require.Equal(t, "application/json", respMetadata.GetJoined("Content-Type"))
|
||||||
require.Equal(t, "My-Header-Value", respMetadata.MustGet("My-Header"))
|
require.Equal(t, "My-Header-Value", respMetadata.GetJoined("My-Header"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -279,10 +278,9 @@ func TestClient_Call_Head(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
md, _ = metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value")
|
ctx = metadata.NewOutgoingContext(
|
||||||
ctx = metadata.NewOutgoingContext(
|
|
||||||
context.Background(),
|
context.Background(),
|
||||||
md,
|
metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value"),
|
||||||
)
|
)
|
||||||
rsp = &response{}
|
rsp = &response{}
|
||||||
respMetadata = metadata.Metadata{}
|
respMetadata = metadata.Metadata{}
|
||||||
@@ -312,8 +310,8 @@ func TestClient_Call_Head(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, proto.Equal(tt.wantRsp, rsp))
|
require.True(t, proto.Equal(tt.wantRsp, rsp))
|
||||||
require.Equal(t, "application/json", respMetadata.MustGet("Content-Type"))
|
require.Equal(t, "application/json", respMetadata.GetJoined("Content-Type"))
|
||||||
require.Equal(t, "My-Header-Value", respMetadata.MustGet("My-Header"))
|
require.Equal(t, "My-Header-Value", respMetadata.GetJoined("My-Header"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -464,10 +462,9 @@ func TestClient_Call_Post(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
md, _ = metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value")
|
ctx = metadata.NewOutgoingContext(
|
||||||
ctx = metadata.NewOutgoingContext(
|
|
||||||
context.Background(),
|
context.Background(),
|
||||||
md,
|
metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value"),
|
||||||
)
|
)
|
||||||
rsp = &response{}
|
rsp = &response{}
|
||||||
respMetadata = metadata.Metadata{}
|
respMetadata = metadata.Metadata{}
|
||||||
@@ -497,8 +494,8 @@ func TestClient_Call_Post(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, proto.Equal(tt.wantRsp, rsp))
|
require.True(t, proto.Equal(tt.wantRsp, rsp))
|
||||||
require.Equal(t, "application/json", respMetadata.MustGet("Content-Type"))
|
require.Equal(t, "application/json", respMetadata.GetJoined("Content-Type"))
|
||||||
require.Equal(t, "My-Header-Value", respMetadata.MustGet("My-Header"))
|
require.Equal(t, "My-Header-Value", respMetadata.GetJoined("My-Header"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -614,10 +611,9 @@ func TestClient_Call_Delete(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
md, _ = metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value")
|
ctx = metadata.NewOutgoingContext(
|
||||||
ctx = metadata.NewOutgoingContext(
|
|
||||||
context.Background(),
|
context.Background(),
|
||||||
md,
|
metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value"),
|
||||||
)
|
)
|
||||||
rsp = &response{}
|
rsp = &response{}
|
||||||
respMetadata = metadata.Metadata{}
|
respMetadata = metadata.Metadata{}
|
||||||
@@ -647,8 +643,8 @@ func TestClient_Call_Delete(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, proto.Equal(tt.wantRsp, rsp))
|
require.True(t, proto.Equal(tt.wantRsp, rsp))
|
||||||
require.Equal(t, "application/json", respMetadata.MustGet("Content-Type"))
|
require.Equal(t, "application/json", respMetadata.GetJoined("Content-Type"))
|
||||||
require.Equal(t, "My-Header-Value", respMetadata.MustGet("My-Header"))
|
require.Equal(t, "My-Header-Value", respMetadata.GetJoined("My-Header"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -771,10 +767,9 @@ func TestClient_Call_APIError_WithErrorsMap(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
md, _ = metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value")
|
ctx = metadata.NewOutgoingContext(
|
||||||
ctx = metadata.NewOutgoingContext(
|
|
||||||
context.Background(),
|
context.Background(),
|
||||||
md,
|
metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value"),
|
||||||
)
|
)
|
||||||
req = &request{UserId: "123", OrderId: 456}
|
req = &request{UserId: "123", OrderId: 456}
|
||||||
rsp = &response{}
|
rsp = &response{}
|
||||||
@@ -808,8 +803,8 @@ func TestClient_Call_APIError_WithErrorsMap(t *testing.T) {
|
|||||||
require.Equal(t, tt.expectedStatus, s)
|
require.Equal(t, tt.expectedStatus, s)
|
||||||
require.Empty(t, rsp)
|
require.Empty(t, rsp)
|
||||||
|
|
||||||
require.Equal(t, "application/json", respMetadata.MustGet("Content-Type"))
|
require.Equal(t, "application/json", respMetadata.GetJoined("Content-Type"))
|
||||||
require.Equal(t, "My-Header-Value", respMetadata.MustGet("My-Header"))
|
require.Equal(t, "My-Header-Value", respMetadata.GetJoined("My-Header"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -863,10 +858,9 @@ func TestClient_Call_APIError_WithoutErrorsMap(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
md, _ = metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value")
|
ctx = metadata.NewOutgoingContext(
|
||||||
ctx = metadata.NewOutgoingContext(
|
|
||||||
context.Background(),
|
context.Background(),
|
||||||
md,
|
metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value"),
|
||||||
)
|
)
|
||||||
req = &request{UserId: "123", OrderId: 456}
|
req = &request{UserId: "123", OrderId: 456}
|
||||||
rsp = &response{}
|
rsp = &response{}
|
||||||
@@ -896,8 +890,8 @@ func TestClient_Call_APIError_WithoutErrorsMap(t *testing.T) {
|
|||||||
require.Equal(t, expectedStatus, s)
|
require.Equal(t, expectedStatus, s)
|
||||||
require.Empty(t, rsp)
|
require.Empty(t, rsp)
|
||||||
|
|
||||||
require.Equal(t, "application/json", respMetadata.MustGet("Content-Type"))
|
require.Equal(t, "application/json", respMetadata.GetJoined("Content-Type"))
|
||||||
require.Equal(t, "My-Header-Value", respMetadata.MustGet("My-Header"))
|
require.Equal(t, "My-Header-Value", respMetadata.GetJoined("My-Header"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_Call_HeadersAndCookies(t *testing.T) {
|
func TestClient_Call_HeadersAndCookies(t *testing.T) {
|
||||||
@@ -954,8 +948,7 @@ func TestClient_Call_HeadersAndCookies(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
prepareMetadata: func() metadata.Metadata {
|
prepareMetadata: func() metadata.Metadata {
|
||||||
md, _ := metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value")
|
return metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value")
|
||||||
return md
|
|
||||||
},
|
},
|
||||||
headerOption: httpcli.Header("Authorization", "true", "My-Header", "true"),
|
headerOption: httpcli.Header("Authorization", "true", "My-Header", "true"),
|
||||||
expectedRsp: &response{Id: "product-id", Name: "product-name"},
|
expectedRsp: &response{Id: "product-id", Name: "product-name"},
|
||||||
@@ -999,8 +992,7 @@ func TestClient_Call_HeadersAndCookies(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
prepareMetadata: func() metadata.Metadata {
|
prepareMetadata: func() metadata.Metadata {
|
||||||
md, _ := metadata.Pairs("Authorization", "Bearer token")
|
return metadata.Pairs("Authorization", "Bearer token")
|
||||||
return md
|
|
||||||
},
|
},
|
||||||
headerOption: httpcli.Header("Authorization", "true", "My-Header", "true"),
|
headerOption: httpcli.Header("Authorization", "true", "My-Header", "true"),
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
@@ -1043,8 +1035,7 @@ func TestClient_Call_HeadersAndCookies(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
prepareMetadata: func() metadata.Metadata {
|
prepareMetadata: func() metadata.Metadata {
|
||||||
md, _ := metadata.Pairs("Cookie", "session_id=abc123; theme=dark")
|
return metadata.Pairs("Cookie", "session_id=abc123; theme=dark")
|
||||||
return md
|
|
||||||
},
|
},
|
||||||
cookieOption: httpcli.Cookie("session_id", "true", "theme", "true"),
|
cookieOption: httpcli.Cookie("session_id", "true", "theme", "true"),
|
||||||
expectedRsp: &response{Id: "product-id", Name: "product-name"},
|
expectedRsp: &response{Id: "product-id", Name: "product-name"},
|
||||||
@@ -1087,8 +1078,7 @@ func TestClient_Call_HeadersAndCookies(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
prepareMetadata: func() metadata.Metadata {
|
prepareMetadata: func() metadata.Metadata {
|
||||||
md, _ := metadata.Pairs("Cookie", "session_id=abc123")
|
return metadata.Pairs("Cookie", "session_id=abc123")
|
||||||
return md
|
|
||||||
},
|
},
|
||||||
cookieOption: httpcli.Cookie("session_id", "true", "theme", "true"),
|
cookieOption: httpcli.Cookie("session_id", "true", "theme", "true"),
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
@@ -1133,12 +1123,11 @@ func TestClient_Call_HeadersAndCookies(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
prepareMetadata: func() metadata.Metadata {
|
prepareMetadata: func() metadata.Metadata {
|
||||||
md, _ := metadata.Pairs(
|
return metadata.Pairs(
|
||||||
"Authorization", "Bearer token",
|
"Authorization", "Bearer token",
|
||||||
"My-Header", "My-Header-Value",
|
"My-Header", "My-Header-Value",
|
||||||
"Cookie", "session_id=abc123; theme=dark",
|
"Cookie", "session_id=abc123; theme=dark",
|
||||||
)
|
)
|
||||||
return md
|
|
||||||
},
|
},
|
||||||
headerOption: httpcli.Header("Authorization", "true", "My-Header", "true"),
|
headerOption: httpcli.Header("Authorization", "true", "My-Header", "true"),
|
||||||
cookieOption: httpcli.Cookie("session_id", "true", "theme", "true"),
|
cookieOption: httpcli.Cookie("session_id", "true", "theme", "true"),
|
||||||
@@ -1190,13 +1179,105 @@ func TestClient_Call_HeadersAndCookies(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, proto.Equal(tt.expectedRsp, rsp))
|
require.True(t, proto.Equal(tt.expectedRsp, rsp))
|
||||||
require.Equal(t, "application/json", respMetadata.MustGet("Content-Type"))
|
require.Equal(t, "application/json", respMetadata.GetJoined("Content-Type"))
|
||||||
require.Equal(t, "My-Header-Value", respMetadata.MustGet("My-Header"))
|
require.Equal(t, "My-Header-Value", respMetadata.GetJoined("My-Header"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClient_Call_SetCookie(t *testing.T) {
|
||||||
|
type (
|
||||||
|
request = pb.Test_Client_Call_Request
|
||||||
|
response = pb.Test_Client_Call_Response
|
||||||
|
)
|
||||||
|
|
||||||
|
serverMock := func() *httptest.Server {
|
||||||
|
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Validate request
|
||||||
|
require.Equal(t, "POST", r.Method)
|
||||||
|
require.Equal(t, "/user/products", r.URL.RequestURI())
|
||||||
|
|
||||||
|
require.Equal(t, "application/json", r.Header.Get("Content-Type"))
|
||||||
|
require.Equal(t, "Bearer token", r.Header.Get("Authorization"))
|
||||||
|
require.Equal(t, "My-Header-Value", r.Header.Get("My-Header"))
|
||||||
|
|
||||||
|
buf, err := io.ReadAll(r.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
c := jsoncodec.NewCodec()
|
||||||
|
|
||||||
|
req := &request{}
|
||||||
|
err = c.Unmarshal(buf, req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, proto.Equal(&request{UserId: "123", OrderId: 456}, req))
|
||||||
|
|
||||||
|
// Return response
|
||||||
|
cookieN1, err := http.ParseSetCookie("sessionid=abc123; Path=/; HttpOnly")
|
||||||
|
require.NoError(t, err)
|
||||||
|
http.SetCookie(w, cookieN1)
|
||||||
|
|
||||||
|
cookieN2, err := http.ParseSetCookie("theme=dark; Path=/; Max-Age=3600")
|
||||||
|
require.NoError(t, err)
|
||||||
|
http.SetCookie(w, cookieN2)
|
||||||
|
|
||||||
|
cookieN3, err := http.ParseSetCookie("lang=en-US; Path=/")
|
||||||
|
require.NoError(t, err)
|
||||||
|
http.SetCookie(w, cookieN3)
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Header().Set("My-Header", "My-Header-Value")
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
server := serverMock()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
httpClient := httpcli.NewClient(
|
||||||
|
client.Codec("application/json", jsoncodec.NewCodec()),
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ctx = metadata.NewOutgoingContext(
|
||||||
|
context.Background(),
|
||||||
|
metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value"),
|
||||||
|
)
|
||||||
|
req = &request{UserId: "123", OrderId: 456}
|
||||||
|
rsp = &response{}
|
||||||
|
|
||||||
|
respMetadata = metadata.Metadata{}
|
||||||
|
)
|
||||||
|
|
||||||
|
opts := []client.CallOption{
|
||||||
|
client.WithAddress(server.URL),
|
||||||
|
client.WithResponseMetadata(&respMetadata),
|
||||||
|
httpcli.Method(http.MethodPost),
|
||||||
|
httpcli.Path("/user/products"),
|
||||||
|
httpcli.Body("*"),
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedSetCookie := []string{"sessionid=abc123; Path=/; HttpOnly", "theme=dark; Path=/; Max-Age=3600", "lang=en-US; Path=/"}
|
||||||
|
|
||||||
|
err := httpClient.Call(
|
||||||
|
ctx,
|
||||||
|
httpClient.NewRequest("test.service", "Test.Call", req),
|
||||||
|
rsp,
|
||||||
|
opts...,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Empty(t, rsp)
|
||||||
|
|
||||||
|
require.Equal(t, "application/json", respMetadata.GetJoined("Content-Type"))
|
||||||
|
require.Equal(t, "My-Header-Value", respMetadata.GetJoined("My-Header"))
|
||||||
|
for i, raw := range respMetadata.Get("Set-Cookie") {
|
||||||
|
cookie, err := http.ParseSetCookie(raw)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedSetCookie[i], cookie.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestClient_Call_NoContent(t *testing.T) {
|
func TestClient_Call_NoContent(t *testing.T) {
|
||||||
type (
|
type (
|
||||||
request = pb.Test_Client_Call_Request
|
request = pb.Test_Client_Call_Request
|
||||||
@@ -1239,10 +1320,9 @@ func TestClient_Call_NoContent(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
md, _ = metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value")
|
ctx = metadata.NewOutgoingContext(
|
||||||
ctx = metadata.NewOutgoingContext(
|
|
||||||
context.Background(),
|
context.Background(),
|
||||||
md,
|
metadata.Pairs("Authorization", "Bearer token", "My-Header", "My-Header-Value"),
|
||||||
)
|
)
|
||||||
req = &request{UserId: "123", OrderId: 456}
|
req = &request{UserId: "123", OrderId: 456}
|
||||||
rsp = &response{}
|
rsp = &response{}
|
||||||
@@ -1267,8 +1347,8 @@ func TestClient_Call_NoContent(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Empty(t, rsp)
|
require.Empty(t, rsp)
|
||||||
|
|
||||||
require.Equal(t, "application/json", respMetadata.MustGet("Content-Type"))
|
require.Equal(t, "application/json", respMetadata.GetJoined("Content-Type"))
|
||||||
require.Equal(t, "My-Header-Value", respMetadata.MustGet("My-Header"))
|
require.Equal(t, "My-Header-Value", respMetadata.GetJoined("My-Header"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_Call_RequestTimeoutError(t *testing.T) {
|
func TestClient_Call_RequestTimeoutError(t *testing.T) {
|
||||||
|
|||||||
23
go.mod
23
go.mod
@@ -1,26 +1,25 @@
|
|||||||
module go.unistack.org/micro-client-http/v3
|
module go.unistack.org/micro-client-http/v4
|
||||||
|
|
||||||
go 1.24.0
|
go 1.23.0
|
||||||
|
|
||||||
toolchain go1.24.3
|
toolchain go1.24.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
go.unistack.org/micro-codec-json/v3 v3.10.3
|
go.unistack.org/micro-codec-json/v4 v4.1.0
|
||||||
go.unistack.org/micro/v3 v3.11.45
|
go.unistack.org/micro/v4 v4.1.19
|
||||||
google.golang.org/protobuf v1.36.10
|
google.golang.org/protobuf v1.36.9
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ash3in/uuidv8 v1.2.0 // indirect
|
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/kr/pretty v0.3.1 // indirect
|
|
||||||
github.com/matoous/go-nanoid v1.5.1 // indirect
|
github.com/matoous/go-nanoid v1.5.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
go.unistack.org/micro-proto/v3 v3.4.1 // indirect
|
github.com/spf13/cast v1.9.2 // indirect
|
||||||
golang.org/x/sys v0.36.0 // indirect
|
go.unistack.org/micro-proto/v4 v4.1.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 // indirect
|
golang.org/x/sys v0.35.0 // indirect
|
||||||
google.golang.org/grpc v1.75.1 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
|
||||||
|
google.golang.org/grpc v1.75.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
39
go.sum
39
go.sum
@@ -1,10 +1,7 @@
|
|||||||
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
|
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
|
|
||||||
github.com/ash3in/uuidv8 v1.2.0 h1:2oogGdtCPwaVtyvPPGin4TfZLtOGE5F+W++E880G6SI=
|
|
||||||
github.com/ash3in/uuidv8 v1.2.0/go.mod h1:BnU0wJBxnzdEKmVg4xckBkD+VZuecTFTUP3M0dWgyY4=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
@@ -17,32 +14,32 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/matoous/go-nanoid v1.5.1 h1:aCjdvTyO9LLnTIi0fgdXhOPPvOHjpXN6Ik9DaNjIct4=
|
github.com/matoous/go-nanoid v1.5.1 h1:aCjdvTyO9LLnTIi0fgdXhOPPvOHjpXN6Ik9DaNjIct4=
|
||||||
github.com/matoous/go-nanoid v1.5.1/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U=
|
github.com/matoous/go-nanoid v1.5.1/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
|
||||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
|
github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE=
|
||||||
|
github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
go.unistack.org/micro-codec-json/v3 v3.10.3 h1:FwSBfJswov30Dyqxp1XfQW1EG4h77uTEe/VGflg6XlY=
|
go.unistack.org/micro-codec-json/v4 v4.1.0 h1:iydeSkt3ee7IPU0dHHKlGN97lw+YFQasBk9rdv0woYA=
|
||||||
go.unistack.org/micro-codec-json/v3 v3.10.3/go.mod h1:26OK5MizMNKhspGC6PRVwpDIp5w1GmRb0nE5eRWWDxA=
|
go.unistack.org/micro-codec-json/v4 v4.1.0/go.mod h1:aUg86elSlURSynTAetDAAXj/VzFDwwcg92QNrRzcvrM=
|
||||||
go.unistack.org/micro-proto/v3 v3.4.1 h1:UTjLSRz2YZuaHk9iSlVqqsA50JQNAEK2ZFboGqtEa9Q=
|
go.unistack.org/micro-proto/v4 v4.1.0 h1:qPwL2n/oqh9RE3RTTDgt28XK3QzV597VugQPaw9lKUk=
|
||||||
go.unistack.org/micro-proto/v3 v3.4.1/go.mod h1:okx/cnOhzuCX0ggl/vToatbCupi0O44diiiLLsZ93Zo=
|
go.unistack.org/micro-proto/v4 v4.1.0/go.mod h1:ArmK7o+uFvxSY3dbJhKBBX4Pm1rhWdLEFf3LxBrMtec=
|
||||||
go.unistack.org/micro/v3 v3.11.45 h1:fjTLZYWgsVf9FIMZBxOg8ios2/tmyimnjZrsrxEUeXU=
|
go.unistack.org/micro/v4 v4.1.19 h1:LKpmSPYvX5B9AkFD7JqMU/U06v5yEWn2bsCG/YKZtZI=
|
||||||
go.unistack.org/micro/v3 v3.11.45/go.mod h1:fDQ8Mu9wubaFP0L8hNQlpzHiEnWN0wbOlawN9HYo0N4=
|
go.unistack.org/micro/v4 v4.1.19/go.mod h1:xleO2M5Yxh4s6I+RUcLrEpUjobefh+71ctrdIfn7TUs=
|
||||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 h1:i8QOKZfYg6AbGVZzUAY3LrNWCKF8O6zFisU9Wl9RER4=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
|
||||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
|
||||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
// --------------------------------------------- HTTPClient option -----------------------------------------------------
|
// --------------------------------------------- HTTPClient option -----------------------------------------------------
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type httpRequest struct {
|
type httpRequest struct {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"go.unistack.org/micro-client-http/v3/status"
|
"go.unistack.org/micro-client-http/v4/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fakeError struct{ s *status.Status }
|
type fakeError struct{ s *status.Status }
|
||||||
|
|||||||
Reference in New Issue
Block a user