@@ -3,6 +3,7 @@ package httpx
3
3
import (
4
4
"context"
5
5
"encoding/json"
6
+ "fmt"
6
7
"net/http"
7
8
"sync"
8
9
@@ -13,8 +14,8 @@ import (
13
14
14
15
var (
15
16
errorHandler func (error ) (int , interface {})
16
- lock sync.RWMutex
17
17
errorHandlerCtx func (context.Context , error ) (int , interface {})
18
+ lock sync.RWMutex
18
19
)
19
20
20
21
// Error writes err into w.
@@ -23,32 +24,26 @@ func Error(w http.ResponseWriter, err error, fns ...func(w http.ResponseWriter,
23
24
handler := errorHandler
24
25
lock .RUnlock ()
25
26
26
- if handler == nil {
27
- if len (fns ) > 0 {
28
- fns [0 ](w , err )
29
- } else if errcode .IsGrpcError (err ) {
30
- // don't unwrap error and get status.Message(),
31
- // it hides the rpc error headers.
32
- http .Error (w , err .Error (), errcode .CodeFromGrpcError (err ))
33
- } else {
34
- http .Error (w , err .Error (), http .StatusBadRequest )
35
- }
27
+ doHandleError (w , err , handler , WriteJson , fns ... )
28
+ }
36
29
37
- return
38
- }
30
+ // ErrorCtx writes err into w.
31
+ func ErrorCtx (ctx context.Context , w http.ResponseWriter , err error ,
32
+ fns ... func (w http.ResponseWriter , err error )) {
33
+ lock .RLock ()
34
+ handlerCtx := errorHandlerCtx
35
+ lock .RUnlock ()
39
36
40
- code , body := handler (err )
41
- if body == nil {
42
- w .WriteHeader (code )
43
- return
37
+ var handler func (error ) (int , interface {})
38
+ if handlerCtx != nil {
39
+ handler = func (err error ) (int , interface {}) {
40
+ return handlerCtx (ctx , err )
41
+ }
44
42
}
45
-
46
- e , ok := body .(error )
47
- if ok {
48
- http .Error (w , e .Error (), code )
49
- } else {
50
- WriteJson (w , code , body )
43
+ writeJson := func (w http.ResponseWriter , code int , v interface {}) {
44
+ WriteJsonCtx (ctx , w , code , v )
51
45
}
46
+ doHandleError (w , err , handler , writeJson , fns ... )
52
47
}
53
48
54
49
// Ok writes HTTP 200 OK into w.
@@ -61,44 +56,47 @@ func OkJson(w http.ResponseWriter, v interface{}) {
61
56
WriteJson (w , http .StatusOK , v )
62
57
}
63
58
59
+ // OkJsonCtx writes v into w with 200 OK.
60
+ func OkJsonCtx (ctx context.Context , w http.ResponseWriter , v interface {}) {
61
+ WriteJsonCtx (ctx , w , http .StatusOK , v )
62
+ }
63
+
64
64
// SetErrorHandler sets the error handler, which is called on calling Error.
65
65
func SetErrorHandler (handler func (error ) (int , interface {})) {
66
66
lock .Lock ()
67
67
defer lock .Unlock ()
68
68
errorHandler = handler
69
69
}
70
70
71
+ // SetErrorHandlerCtx sets the error handler, which is called on calling Error.
72
+ func SetErrorHandlerCtx (handlerCtx func (context.Context , error ) (int , interface {})) {
73
+ lock .Lock ()
74
+ defer lock .Unlock ()
75
+ errorHandlerCtx = handlerCtx
76
+ }
77
+
71
78
// WriteJson writes v as json string into w with code.
72
79
func WriteJson (w http.ResponseWriter , code int , v interface {}) {
73
- bs , err := json .Marshal (v )
74
- if err != nil {
75
- http .Error (w , err .Error (), http .StatusInternalServerError )
76
- return
80
+ if err := doWriteJson (w , code , v ); err != nil {
81
+ logx .Error (err )
77
82
}
83
+ }
78
84
79
- w .Header ().Set (ContentType , header .JsonContentType )
80
- w .WriteHeader (code )
81
-
82
- if n , err := w .Write (bs ); err != nil {
83
- // http.ErrHandlerTimeout has been handled by http.TimeoutHandler,
84
- // so it's ignored here.
85
- if err != http .ErrHandlerTimeout {
86
- logx .Errorf ("write response failed, error: %s" , err )
87
- }
88
- } else if n < len (bs ) {
89
- logx .Errorf ("actual bytes: %d, written bytes: %d" , len (bs ), n )
85
+ // WriteJsonCtx writes v as json string into w with code.
86
+ func WriteJsonCtx (ctx context.Context , w http.ResponseWriter , code int , v interface {}) {
87
+ if err := doWriteJson (w , code , v ); err != nil {
88
+ logx .WithContext (ctx ).Error (err )
90
89
}
91
90
}
92
91
93
- // Error writes err into w.
94
- func ErrorCtx (ctx context.Context , w http.ResponseWriter , err error , fns ... func (w http.ResponseWriter , err error )) {
95
- lock .RLock ()
96
- handlerCtx := errorHandlerCtx
97
- lock .RUnlock ()
98
-
99
- if handlerCtx == nil {
92
+ func doHandleError (w http.ResponseWriter , err error , handler func (error ) (int , interface {}),
93
+ writeJson func (w http.ResponseWriter , code int , v interface {}),
94
+ fns ... func (w http.ResponseWriter , err error )) {
95
+ if handler == nil {
100
96
if len (fns ) > 0 {
101
- fns [0 ](w , err )
97
+ for _ , fn := range fns {
98
+ fn (w , err )
99
+ }
102
100
} else if errcode .IsGrpcError (err ) {
103
101
// don't unwrap error and get status.Message(),
104
102
// it hides the rpc error headers.
@@ -110,7 +108,7 @@ func ErrorCtx(ctx context.Context, w http.ResponseWriter, err error, fns ...func
110
108
return
111
109
}
112
110
113
- code , body := handlerCtx ( ctx , err )
111
+ code , body := handler ( err )
114
112
if body == nil {
115
113
w .WriteHeader (code )
116
114
return
@@ -120,21 +118,15 @@ func ErrorCtx(ctx context.Context, w http.ResponseWriter, err error, fns ...func
120
118
if ok {
121
119
http .Error (w , e .Error (), code )
122
120
} else {
123
- WriteJsonCtx ( ctx , w , code , body )
121
+ writeJson ( w , code , body )
124
122
}
125
123
}
126
124
127
- // OkJson writes v into w with 200 OK.
128
- func OkJsonCtx (ctx context.Context , w http.ResponseWriter , v interface {}) {
129
- WriteJsonCtx (ctx , w , http .StatusOK , v )
130
- }
131
-
132
- // WriteJson writes v as json string into w with code.
133
- func WriteJsonCtx (ctx context.Context , w http.ResponseWriter , code int , v interface {}) {
125
+ func doWriteJson (w http.ResponseWriter , code int , v interface {}) error {
134
126
bs , err := json .Marshal (v )
135
127
if err != nil {
136
128
http .Error (w , err .Error (), http .StatusInternalServerError )
137
- return
129
+ return fmt . Errorf ( "marshal json failed, error: %w" , err )
138
130
}
139
131
140
132
w .Header ().Set (ContentType , header .JsonContentType )
@@ -144,16 +136,11 @@ func WriteJsonCtx(ctx context.Context, w http.ResponseWriter, code int, v interf
144
136
// http.ErrHandlerTimeout has been handled by http.TimeoutHandler,
145
137
// so it's ignored here.
146
138
if err != http .ErrHandlerTimeout {
147
- logx . WithContext ( ctx ). Errorf ("write response failed, error: %s " , err )
139
+ return fmt . Errorf ("write response failed, error: %w " , err )
148
140
}
149
141
} else if n < len (bs ) {
150
- logx . WithContext ( ctx ) .Errorf ("actual bytes: %d, written bytes: %d" , len (bs ), n )
142
+ return fmt .Errorf ("actual bytes: %d, written bytes: %d" , len (bs ), n )
151
143
}
152
- }
153
144
154
- // SetErrorHandler sets the error handler, which is called on calling Error.
155
- func SetErrorHandlerCtx (handlerCtx func (context.Context , error ) (int , interface {})) {
156
- lock .Lock ()
157
- defer lock .Unlock ()
158
- errorHandlerCtx = handlerCtx
145
+ return nil
159
146
}
0 commit comments