transport/http: add http route (#1029)
* add http route * fix http context * add HTTP middleware Co-authored-by: longXboy <longxboyhi@gmail.com>pull/1036/head
parent
4a257c1a34
commit
1b13abd136
@ -0,0 +1,6 @@ |
||||
package main |
||||
|
||||
const ( |
||||
// Version is protoc-gen-go-http version
|
||||
Version = "v2.0.0-rc3" |
||||
) |
@ -0,0 +1,80 @@ |
||||
package json |
||||
|
||||
import ( |
||||
"bytes" |
||||
"strings" |
||||
"testing" |
||||
) |
||||
|
||||
type testEmbed struct { |
||||
Level1a int `json:"a"` |
||||
Level1b int `json:"b"` |
||||
Level1c int `json:"c"` |
||||
} |
||||
|
||||
type testMessage struct { |
||||
Field1 string `json:"a"` |
||||
Field2 string `json:"b"` |
||||
Field3 string `json:"c"` |
||||
Embed *testEmbed `json:"embed,omitempty"` |
||||
} |
||||
|
||||
func TestJSON_Marshal(t *testing.T) { |
||||
tests := []struct { |
||||
input interface{} |
||||
expect string |
||||
}{ |
||||
{ |
||||
input: &testMessage{}, |
||||
expect: `{"a":"","b":"","c":""}`, |
||||
}, |
||||
{ |
||||
input: &testMessage{Field1: "a", Field2: "b", Field3: "c"}, |
||||
expect: `{"a":"a","b":"b","c":"c"}`, |
||||
}, |
||||
} |
||||
for _, v := range tests { |
||||
data, err := (codec{}).Marshal(v.input) |
||||
if err != nil { |
||||
t.Errorf("marshal(%#v): %s", v.input, err) |
||||
} |
||||
if got, want := string(data), v.expect; got != want { |
||||
if strings.Contains(want, "\n") { |
||||
t.Errorf("marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", v.input, got, want) |
||||
} else { |
||||
t.Errorf("marshal(%#v):\nhave %#q\nwant %#q", v.input, got, want) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestJSON_Unmarshal(t *testing.T) { |
||||
p := &testMessage{} |
||||
tests := []struct { |
||||
input string |
||||
expect interface{} |
||||
}{ |
||||
{ |
||||
input: `{"a":"","b":"","c":""}`, |
||||
expect: &testMessage{}, |
||||
}, |
||||
{ |
||||
input: `{"a":"a","b":"b","c":"c"}`, |
||||
expect: &p, |
||||
}, |
||||
} |
||||
for _, v := range tests { |
||||
want := []byte(v.input) |
||||
err := (codec{}).Unmarshal(want, &v.expect) |
||||
if err != nil { |
||||
t.Errorf("marshal(%#v): %s", v.input, err) |
||||
} |
||||
got, err := codec{}.Marshal(v.expect) |
||||
if err != nil { |
||||
t.Errorf("marshal(%#v): %s", v.input, err) |
||||
} |
||||
if !bytes.Equal(got, want) { |
||||
t.Errorf("marshal(%#v):\nhave %#q\nwant %#q", v.input, got, want) |
||||
} |
||||
} |
||||
} |
@ -1,134 +0,0 @@ |
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.15.7
|
||||
// source: blog/api/blog/v1/error_reason.proto
|
||||
|
||||
package v1 |
||||
|
||||
import ( |
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect" |
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl" |
||||
reflect "reflect" |
||||
sync "sync" |
||||
) |
||||
|
||||
const ( |
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) |
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) |
||||
) |
||||
|
||||
type ErrorReason int32 |
||||
|
||||
const ( |
||||
ErrorReason_TITLE_MISSING ErrorReason = 0 |
||||
ErrorReason_CONTENTMISSING ErrorReason = 1 |
||||
) |
||||
|
||||
// Enum value maps for ErrorReason.
|
||||
var ( |
||||
ErrorReason_name = map[int32]string{ |
||||
0: "TITLE_MISSING", |
||||
1: "CONTENTMISSING", |
||||
} |
||||
ErrorReason_value = map[string]int32{ |
||||
"TITLE_MISSING": 0, |
||||
"CONTENTMISSING": 1, |
||||
} |
||||
) |
||||
|
||||
func (x ErrorReason) Enum() *ErrorReason { |
||||
p := new(ErrorReason) |
||||
*p = x |
||||
return p |
||||
} |
||||
|
||||
func (x ErrorReason) String() string { |
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) |
||||
} |
||||
|
||||
func (ErrorReason) Descriptor() protoreflect.EnumDescriptor { |
||||
return file_blog_api_blog_v1_error_reason_proto_enumTypes[0].Descriptor() |
||||
} |
||||
|
||||
func (ErrorReason) Type() protoreflect.EnumType { |
||||
return &file_blog_api_blog_v1_error_reason_proto_enumTypes[0] |
||||
} |
||||
|
||||
func (x ErrorReason) Number() protoreflect.EnumNumber { |
||||
return protoreflect.EnumNumber(x) |
||||
} |
||||
|
||||
// Deprecated: Use ErrorReason.Descriptor instead.
|
||||
func (ErrorReason) EnumDescriptor() ([]byte, []int) { |
||||
return file_blog_api_blog_v1_error_reason_proto_rawDescGZIP(), []int{0} |
||||
} |
||||
|
||||
var File_blog_api_blog_v1_error_reason_proto protoreflect.FileDescriptor |
||||
|
||||
var file_blog_api_blog_v1_error_reason_proto_rawDesc = []byte{ |
||||
0x0a, 0x23, 0x62, 0x6c, 0x6f, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x62, 0x6c, 0x6f, 0x67, 0x2f, |
||||
0x76, 0x31, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2e, |
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x61, 0x70, 0x69, 0x2e, 0x62, 0x6c, 0x6f, 0x67, 0x2e, |
||||
0x76, 0x31, 0x2a, 0x34, 0x0a, 0x0b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, |
||||
0x6e, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, |
||||
0x4e, 0x47, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x4d, |
||||
0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x42, 0x57, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x67, |
||||
0x2e, 0x76, 0x31, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x50, 0x01, 0x5a, 0x33, 0x67, 0x69, |
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, |
||||
0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, |
||||
0x65, 0x73, 0x2f, 0x62, 0x6c, 0x6f, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x76, |
||||
0x31, 0xa2, 0x02, 0x0d, 0x41, 0x50, 0x49, 0x42, 0x6c, 0x6f, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, |
||||
0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, |
||||
} |
||||
|
||||
var ( |
||||
file_blog_api_blog_v1_error_reason_proto_rawDescOnce sync.Once |
||||
file_blog_api_blog_v1_error_reason_proto_rawDescData = file_blog_api_blog_v1_error_reason_proto_rawDesc |
||||
) |
||||
|
||||
func file_blog_api_blog_v1_error_reason_proto_rawDescGZIP() []byte { |
||||
file_blog_api_blog_v1_error_reason_proto_rawDescOnce.Do(func() { |
||||
file_blog_api_blog_v1_error_reason_proto_rawDescData = protoimpl.X.CompressGZIP(file_blog_api_blog_v1_error_reason_proto_rawDescData) |
||||
}) |
||||
return file_blog_api_blog_v1_error_reason_proto_rawDescData |
||||
} |
||||
|
||||
var file_blog_api_blog_v1_error_reason_proto_enumTypes = make([]protoimpl.EnumInfo, 1) |
||||
var file_blog_api_blog_v1_error_reason_proto_goTypes = []interface{}{ |
||||
(ErrorReason)(0), // 0: api.blog.v1.ErrorReason
|
||||
} |
||||
var file_blog_api_blog_v1_error_reason_proto_depIdxs = []int32{ |
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
} |
||||
|
||||
func init() { file_blog_api_blog_v1_error_reason_proto_init() } |
||||
func file_blog_api_blog_v1_error_reason_proto_init() { |
||||
if File_blog_api_blog_v1_error_reason_proto != nil { |
||||
return |
||||
} |
||||
type x struct{} |
||||
out := protoimpl.TypeBuilder{ |
||||
File: protoimpl.DescBuilder{ |
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), |
||||
RawDescriptor: file_blog_api_blog_v1_error_reason_proto_rawDesc, |
||||
NumEnums: 1, |
||||
NumMessages: 0, |
||||
NumExtensions: 0, |
||||
NumServices: 0, |
||||
}, |
||||
GoTypes: file_blog_api_blog_v1_error_reason_proto_goTypes, |
||||
DependencyIndexes: file_blog_api_blog_v1_error_reason_proto_depIdxs, |
||||
EnumInfos: file_blog_api_blog_v1_error_reason_proto_enumTypes, |
||||
}.Build() |
||||
File_blog_api_blog_v1_error_reason_proto = out.File |
||||
file_blog_api_blog_v1_error_reason_proto_rawDesc = nil |
||||
file_blog_api_blog_v1_error_reason_proto_goTypes = nil |
||||
file_blog_api_blog_v1_error_reason_proto_depIdxs = nil |
||||
} |
@ -1,14 +0,0 @@ |
||||
syntax = "proto3"; |
||||
|
||||
package api.blog.v1; |
||||
|
||||
// 多语言特定包名,用于源代码引用 |
||||
option go_package = "github.com/go-kratos/kratos/examples/blog/api/v1;v1"; |
||||
option java_multiple_files = true; |
||||
option java_package = "blog.v1.errors"; |
||||
option objc_class_prefix = "APIBlogErrors"; |
||||
|
||||
enum ErrorReason { |
||||
TITLE_MISSING = 0; |
||||
CONTENTMISSING = 1; |
||||
} |
@ -1,52 +0,0 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"context" |
||||
"log" |
||||
|
||||
"github.com/go-kratos/kratos/v2" |
||||
"github.com/go-kratos/kratos/v2/transport/http" |
||||
"github.com/gorilla/mux" |
||||
) |
||||
|
||||
// User is a user model.
|
||||
type User struct { |
||||
ID string `json:"id"` |
||||
Name string `json:"name"` |
||||
} |
||||
|
||||
// UserService is a user service.
|
||||
type UserService struct{ users map[string]*User } |
||||
|
||||
// Get get a user from memory.
|
||||
func (u *UserService) Get(ctx context.Context, user *User) (*User, error) { |
||||
return u.users[user.ID], nil |
||||
} |
||||
|
||||
// Add add a user to memory.
|
||||
func (u *UserService) Add(ctx context.Context, user *User) (*User, error) { |
||||
u.users[user.ID] = user |
||||
return user, nil |
||||
} |
||||
|
||||
func main() { |
||||
us := &UserService{ |
||||
users: make(map[string]*User), |
||||
} |
||||
router := mux.NewRouter() |
||||
router.Handle("/users/add", http.NewHandler(us.Add)).Methods("POST") |
||||
router.Handle("/users/detail", http.NewHandler(us.Get)).Methods("GET") |
||||
|
||||
httpSrv := http.NewServer(http.Address(":8000")) |
||||
httpSrv.HandlePrefix("/", router) |
||||
|
||||
app := kratos.New( |
||||
kratos.Name("handler"), |
||||
kratos.Server( |
||||
httpSrv, |
||||
), |
||||
) |
||||
if err := app.Run(); err != nil { |
||||
log.Println(err) |
||||
} |
||||
} |
@ -0,0 +1,28 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/go-kratos/kratos/examples/helloworld/helloworld" |
||||
"github.com/go-kratos/kratos/v2/transport" |
||||
"github.com/go-kratos/kratos/v2/transport/http" |
||||
"github.com/go-kratos/kratos/v2/transport/http/binding" |
||||
) |
||||
|
||||
func sayHelloHandler(ctx http.Context) error { |
||||
var in helloworld.HelloRequest |
||||
if err := ctx.Bind(&in); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// binding /hello/{name} to in.Name
|
||||
if err := binding.BindVars(ctx.Vars(), &in); err != nil { |
||||
return err |
||||
} |
||||
|
||||
transport.SetOperation(ctx, "/helloworld.Greeter/SayHello") |
||||
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return &helloworld.HelloReply{Message: "test:" + req.(*helloworld.HelloRequest).Name}, nil |
||||
}) |
||||
return ctx.Returns(h(ctx, &in)) |
||||
} |
@ -0,0 +1,40 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"github.com/go-kratos/kratos/examples/helloworld/helloworld" |
||||
"github.com/go-kratos/kratos/v2" |
||||
"github.com/go-kratos/kratos/v2/transport/http" |
||||
) |
||||
|
||||
// this example shows how to add middlewares,
|
||||
// execution order is globalFilter(http) --> routeFilter(http) --> pathFilter(http) --> serviceFilter(service)
|
||||
func main() { |
||||
s := &server{} |
||||
httpSrv := http.NewServer( |
||||
http.Address(":8000"), |
||||
http.Middleware( |
||||
// add service filter
|
||||
serviceMiddleware, |
||||
serviceMiddleware2, |
||||
), |
||||
// add global filter
|
||||
http.Filter(globalFilter, globalFilter2), |
||||
) |
||||
// register http hanlder to http server
|
||||
helloworld.RegisterGreeterHTTPServer(httpSrv, s) |
||||
|
||||
// add route filter
|
||||
r := httpSrv.Route("/", routeFilter, routeFilter2) |
||||
// add path filter to custom route
|
||||
r.GET("/hello/{name}", sayHelloHandler, pathFilter, pathFilter2) |
||||
|
||||
app := kratos.New( |
||||
kratos.Name("helloworld"), |
||||
kratos.Server( |
||||
httpSrv, |
||||
), |
||||
) |
||||
if err := app.Run(); err != nil { |
||||
panic(err) |
||||
} |
||||
} |
@ -0,0 +1,75 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"net/http" |
||||
|
||||
"github.com/go-kratos/kratos/v2/middleware" |
||||
) |
||||
|
||||
func globalFilter(next http.Handler) http.Handler { |
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
||||
fmt.Println("global filter in") |
||||
next.ServeHTTP(w, r) |
||||
fmt.Println("global filter out") |
||||
}) |
||||
} |
||||
|
||||
func globalFilter2(next http.Handler) http.Handler { |
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
||||
fmt.Println("global filter 2 in") |
||||
next.ServeHTTP(w, r) |
||||
fmt.Println("global filter 2 out") |
||||
}) |
||||
} |
||||
|
||||
func routeFilter(next http.Handler) http.Handler { |
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
||||
fmt.Println("route filter in") |
||||
next.ServeHTTP(w, r) |
||||
fmt.Println("route filter out") |
||||
}) |
||||
} |
||||
|
||||
func routeFilter2(next http.Handler) http.Handler { |
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
||||
fmt.Println("route filter 2 in") |
||||
next.ServeHTTP(w, r) |
||||
fmt.Println("route filter 2 out") |
||||
}) |
||||
} |
||||
|
||||
func pathFilter(next http.Handler) http.Handler { |
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
||||
fmt.Println("path filter in") |
||||
next.ServeHTTP(w, r) |
||||
fmt.Println("path filter out") |
||||
}) |
||||
} |
||||
|
||||
func pathFilter2(next http.Handler) http.Handler { |
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
||||
fmt.Println("path filter 2 in") |
||||
next.ServeHTTP(w, r) |
||||
fmt.Println("path filter 2 out") |
||||
}) |
||||
} |
||||
|
||||
func serviceMiddleware(handler middleware.Handler) middleware.Handler { |
||||
return func(ctx context.Context, req interface{}) (reply interface{}, err error) { |
||||
fmt.Println("service middleware in") |
||||
reply, err = handler(ctx, req) |
||||
fmt.Println("service middleware out") |
||||
return |
||||
} |
||||
} |
||||
|
||||
func serviceMiddleware2(handler middleware.Handler) middleware.Handler { |
||||
return func(ctx context.Context, req interface{}) (reply interface{}, err error) { |
||||
fmt.Println("service middleware 2 in") |
||||
reply, err = handler(ctx, req) |
||||
fmt.Println("service middleware 2 out") |
||||
return |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
|
||||
"github.com/go-kratos/kratos/examples/helloworld/helloworld" |
||||
"github.com/go-kratos/kratos/v2/errors" |
||||
) |
||||
|
||||
// server is used to implement helloworld.GreeterServer.
|
||||
type server struct { |
||||
helloworld.UnimplementedGreeterServer |
||||
} |
||||
|
||||
// SayHello implements helloworld.GreeterServer
|
||||
func (s *server) SayHello(ctx context.Context, in *helloworld.HelloRequest) (*helloworld.HelloReply, error) { |
||||
if in.Name == "error" { |
||||
return nil, errors.BadRequest("custom_error", fmt.Sprintf("invalid argument %s", in.Name)) |
||||
} |
||||
if in.Name == "panic" { |
||||
panic("grpc panic") |
||||
} |
||||
return &helloworld.HelloReply{Message: fmt.Sprintf("Hello %+v", in.Name)}, nil |
||||
} |
@ -1,380 +0,0 @@ |
||||
// Code generated by protoc-gen-go-http. DO NOT EDIT.
|
||||
|
||||
package testproto |
||||
|
||||
import ( |
||||
context "context" |
||||
middleware "github.com/go-kratos/kratos/v2/middleware" |
||||
transport "github.com/go-kratos/kratos/v2/transport" |
||||
http1 "github.com/go-kratos/kratos/v2/transport/http" |
||||
binding "github.com/go-kratos/kratos/v2/transport/http/binding" |
||||
mux "github.com/gorilla/mux" |
||||
http "net/http" |
||||
) |
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the kratos package it is being compiled against.
|
||||
var _ = new(http.Request) |
||||
var _ = new(context.Context) |
||||
var _ = new(middleware.Middleware) |
||||
var _ = new(transport.Transporter) |
||||
var _ = binding.BindVars |
||||
var _ = mux.NewRouter |
||||
|
||||
const _ = http1.SupportPackageIsVersion1 |
||||
|
||||
type EchoServiceHandler interface { |
||||
Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) |
||||
|
||||
EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) |
||||
|
||||
EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) |
||||
|
||||
EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) |
||||
|
||||
EchoResponseBody(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) |
||||
} |
||||
|
||||
func NewEchoServiceHandler(srv EchoServiceHandler, opts ...http1.HandleOption) http.Handler { |
||||
h := http1.DefaultHandleOptions() |
||||
for _, o := range opts { |
||||
o(&h) |
||||
} |
||||
r := mux.NewRouter() |
||||
|
||||
r.HandleFunc("/v1/example/echo/{id}/{num}", func(w http.ResponseWriter, r *http.Request) { |
||||
var in SimpleMessage |
||||
if err := h.Decode(r, &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
if err := binding.BindVars(mux.Vars(r), &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
next := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.Echo(ctx, req.(*SimpleMessage)) |
||||
} |
||||
if h.Middleware != nil { |
||||
next = h.Middleware(next) |
||||
} |
||||
ctx := r.Context() |
||||
transport.SetMethod(ctx, "/testproto.EchoService/Echo") |
||||
out, err := next(ctx, &in) |
||||
if err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
if err := h.Encode(w, r, reply); err != nil { |
||||
h.Error(w, r, err) |
||||
} |
||||
}).Methods("GET") |
||||
|
||||
r.HandleFunc("/v1/example/echo/{id}/{num}/{lang}", func(w http.ResponseWriter, r *http.Request) { |
||||
var in SimpleMessage |
||||
if err := h.Decode(r, &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
if err := binding.BindVars(mux.Vars(r), &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
next := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.Echo(ctx, req.(*SimpleMessage)) |
||||
} |
||||
if h.Middleware != nil { |
||||
next = h.Middleware(next) |
||||
} |
||||
ctx := r.Context() |
||||
transport.SetMethod(ctx, "/testproto.EchoService/Echo") |
||||
out, err := next(ctx, &in) |
||||
if err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
if err := h.Encode(w, r, reply); err != nil { |
||||
h.Error(w, r, err) |
||||
} |
||||
}).Methods("GET") |
||||
|
||||
r.HandleFunc("/v1/example/echo1/{id}/{line_num}/{status.note}", func(w http.ResponseWriter, r *http.Request) { |
||||
var in SimpleMessage |
||||
if err := h.Decode(r, &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
if err := binding.BindVars(mux.Vars(r), &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
next := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.Echo(ctx, req.(*SimpleMessage)) |
||||
} |
||||
if h.Middleware != nil { |
||||
next = h.Middleware(next) |
||||
} |
||||
ctx := r.Context() |
||||
transport.SetMethod(ctx, "/testproto.EchoService/Echo") |
||||
out, err := next(ctx, &in) |
||||
if err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
if err := h.Encode(w, r, reply); err != nil { |
||||
h.Error(w, r, err) |
||||
} |
||||
}).Methods("GET") |
||||
|
||||
r.HandleFunc("/v1/example/echo2/{no.note}", func(w http.ResponseWriter, r *http.Request) { |
||||
var in SimpleMessage |
||||
if err := h.Decode(r, &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
if err := binding.BindVars(mux.Vars(r), &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
next := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.Echo(ctx, req.(*SimpleMessage)) |
||||
} |
||||
if h.Middleware != nil { |
||||
next = h.Middleware(next) |
||||
} |
||||
ctx := r.Context() |
||||
transport.SetMethod(ctx, "/testproto.EchoService/Echo") |
||||
out, err := next(ctx, &in) |
||||
if err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
if err := h.Encode(w, r, reply); err != nil { |
||||
h.Error(w, r, err) |
||||
} |
||||
}).Methods("GET") |
||||
|
||||
r.HandleFunc("/v1/example/echo/{id}", func(w http.ResponseWriter, r *http.Request) { |
||||
var in SimpleMessage |
||||
if err := h.Decode(r, &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
if err := binding.BindVars(mux.Vars(r), &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
next := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.Echo(ctx, req.(*SimpleMessage)) |
||||
} |
||||
if h.Middleware != nil { |
||||
next = h.Middleware(next) |
||||
} |
||||
ctx := r.Context() |
||||
transport.SetMethod(ctx, "/testproto.EchoService/Echo") |
||||
out, err := next(ctx, &in) |
||||
if err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
if err := h.Encode(w, r, reply); err != nil { |
||||
h.Error(w, r, err) |
||||
} |
||||
}).Methods("POST") |
||||
|
||||
r.HandleFunc("/v1/example/echo_body", func(w http.ResponseWriter, r *http.Request) { |
||||
var in SimpleMessage |
||||
if err := h.Decode(r, &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
next := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.EchoBody(ctx, req.(*SimpleMessage)) |
||||
} |
||||
if h.Middleware != nil { |
||||
next = h.Middleware(next) |
||||
} |
||||
ctx := r.Context() |
||||
transport.SetMethod(ctx, "/testproto.EchoService/EchoBody") |
||||
out, err := next(ctx, &in) |
||||
if err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
if err := h.Encode(w, r, reply); err != nil { |
||||
h.Error(w, r, err) |
||||
} |
||||
}).Methods("POST") |
||||
|
||||
r.HandleFunc("/v1/example/echo_response_body", func(w http.ResponseWriter, r *http.Request) { |
||||
var in DynamicMessageUpdate |
||||
if err := h.Decode(r, &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
next := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.EchoResponseBody(ctx, req.(*DynamicMessageUpdate)) |
||||
} |
||||
if h.Middleware != nil { |
||||
next = h.Middleware(next) |
||||
} |
||||
ctx := r.Context() |
||||
transport.SetMethod(ctx, "/testproto.EchoService/EchoResponseBody") |
||||
out, err := next(ctx, &in) |
||||
if err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
reply := out.(*DynamicMessageUpdate) |
||||
if err := h.Encode(w, r, reply.Body); err != nil { |
||||
h.Error(w, r, err) |
||||
} |
||||
}).Methods("POST") |
||||
|
||||
r.HandleFunc("/v1/example/echo_delete/{id}/{num}", func(w http.ResponseWriter, r *http.Request) { |
||||
var in SimpleMessage |
||||
if err := h.Decode(r, &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
if err := binding.BindVars(mux.Vars(r), &in); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
next := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.EchoDelete(ctx, req.(*SimpleMessage)) |
||||
} |
||||
if h.Middleware != nil { |
||||
next = h.Middleware(next) |
||||
} |
||||
ctx := r.Context() |
||||
transport.SetMethod(ctx, "/testproto.EchoService/EchoDelete") |
||||
out, err := next(ctx, &in) |
||||
if err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
if err := h.Encode(w, r, reply); err != nil { |
||||
h.Error(w, r, err) |
||||
} |
||||
}).Methods("DELETE") |
||||
|
||||
r.HandleFunc("/v1/example/echo_patch", func(w http.ResponseWriter, r *http.Request) { |
||||
var in DynamicMessageUpdate |
||||
if err := h.Decode(r, &in.Body); err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
|
||||
next := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.EchoPatch(ctx, req.(*DynamicMessageUpdate)) |
||||
} |
||||
if h.Middleware != nil { |
||||
next = h.Middleware(next) |
||||
} |
||||
ctx := r.Context() |
||||
transport.SetMethod(ctx, "/testproto.EchoService/EchoPatch") |
||||
out, err := next(ctx, &in) |
||||
if err != nil { |
||||
h.Error(w, r, err) |
||||
return |
||||
} |
||||
reply := out.(*DynamicMessageUpdate) |
||||
if err := h.Encode(w, r, reply); err != nil { |
||||
h.Error(w, r, err) |
||||
} |
||||
}).Methods("PATCH") |
||||
|
||||
return r |
||||
} |
||||
|
||||
type EchoServiceHTTPClient interface { |
||||
Echo(ctx context.Context, req *SimpleMessage, opts ...http1.CallOption) (rsp *SimpleMessage, err error) |
||||
|
||||
EchoBody(ctx context.Context, req *SimpleMessage, opts ...http1.CallOption) (rsp *SimpleMessage, err error) |
||||
|
||||
EchoDelete(ctx context.Context, req *SimpleMessage, opts ...http1.CallOption) (rsp *SimpleMessage, err error) |
||||
|
||||
EchoPatch(ctx context.Context, req *DynamicMessageUpdate, opts ...http1.CallOption) (rsp *DynamicMessageUpdate, err error) |
||||
|
||||
EchoResponseBody(ctx context.Context, req *DynamicMessageUpdate, opts ...http1.CallOption) (rsp *DynamicMessageUpdate, err error) |
||||
} |
||||
|
||||
type EchoServiceHTTPClientImpl struct { |
||||
cc *http1.Client |
||||
} |
||||
|
||||
func NewEchoServiceHTTPClient(client *http1.Client) EchoServiceHTTPClient { |
||||
return &EchoServiceHTTPClientImpl{client} |
||||
} |
||||
|
||||
func (c *EchoServiceHTTPClientImpl) Echo(ctx context.Context, in *SimpleMessage, opts ...http1.CallOption) (*SimpleMessage, error) { |
||||
var out SimpleMessage |
||||
path := binding.EncodePath("POST", "/v1/example/echo/{id}", in) |
||||
opts = append(opts, http1.Method("/testproto.EchoService/Echo")) |
||||
|
||||
err := c.cc.Invoke(ctx, "POST", path, nil, &out, opts...) |
||||
|
||||
return &out, err |
||||
} |
||||
|
||||
func (c *EchoServiceHTTPClientImpl) EchoBody(ctx context.Context, in *SimpleMessage, opts ...http1.CallOption) (*SimpleMessage, error) { |
||||
var out SimpleMessage |
||||
path := binding.EncodePath("POST", "/v1/example/echo_body", in) |
||||
opts = append(opts, http1.Method("/testproto.EchoService/EchoBody")) |
||||
|
||||
err := c.cc.Invoke(ctx, "POST", path, in, &out, opts...) |
||||
|
||||
return &out, err |
||||
} |
||||
|
||||
func (c *EchoServiceHTTPClientImpl) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...http1.CallOption) (*SimpleMessage, error) { |
||||
var out SimpleMessage |
||||
path := binding.EncodePath("DELETE", "/v1/example/echo_delete/{id}/{num}", in) |
||||
opts = append(opts, http1.Method("/testproto.EchoService/EchoDelete")) |
||||
|
||||
err := c.cc.Invoke(ctx, "DELETE", path, nil, &out, opts...) |
||||
|
||||
return &out, err |
||||
} |
||||
|
||||
func (c *EchoServiceHTTPClientImpl) EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...http1.CallOption) (*DynamicMessageUpdate, error) { |
||||
var out DynamicMessageUpdate |
||||
path := binding.EncodePath("PATCH", "/v1/example/echo_patch", in) |
||||
opts = append(opts, http1.Method("/testproto.EchoService/EchoPatch")) |
||||
|
||||
err := c.cc.Invoke(ctx, "PATCH", path, in.Body, &out, opts...) |
||||
|
||||
return &out, err |
||||
} |
||||
|
||||
func (c *EchoServiceHTTPClientImpl) EchoResponseBody(ctx context.Context, in *DynamicMessageUpdate, opts ...http1.CallOption) (*DynamicMessageUpdate, error) { |
||||
var out DynamicMessageUpdate |
||||
path := binding.EncodePath("POST", "/v1/example/echo_response_body", in) |
||||
opts = append(opts, http1.Method("/testproto.EchoService/EchoResponseBody")) |
||||
|
||||
err := c.cc.Invoke(ctx, "POST", path, in, &out.Body, opts...) |
||||
|
||||
return &out, err |
||||
} |
@ -1,86 +0,0 @@ |
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.15.7
|
||||
// source: proto/stream.proto
|
||||
|
||||
package testproto |
||||
|
||||
import ( |
||||
_ "google.golang.org/genproto/googleapis/api/annotations" |
||||
httpbody "google.golang.org/genproto/googleapis/api/httpbody" |
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect" |
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl" |
||||
emptypb "google.golang.org/protobuf/types/known/emptypb" |
||||
reflect "reflect" |
||||
) |
||||
|
||||
const ( |
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) |
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) |
||||
) |
||||
|
||||
var File_proto_stream_proto protoreflect.FileDescriptor |
||||
|
||||
var file_proto_stream_proto_rawDesc = []byte{ |
||||
0x0a, 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x70, |
||||
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, |
||||
0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, |
||||
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, |
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x62, 0x6f, |
||||
0x64, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, |
||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, |
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x69, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, |
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x08, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, |
||||
0x61, 0x64, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, |
||||
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, |
||||
0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, |
||||
0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, |
||||
0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x30, 0x01, |
||||
0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, |
||||
0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, |
||||
0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, |
||||
0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, |
||||
0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, |
||||
0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, |
||||
} |
||||
|
||||
var file_proto_stream_proto_goTypes = []interface{}{ |
||||
(*emptypb.Empty)(nil), // 0: google.protobuf.Empty
|
||||
(*httpbody.HttpBody)(nil), // 1: google.api.HttpBody
|
||||
} |
||||
var file_proto_stream_proto_depIdxs = []int32{ |
||||
0, // 0: testproto.StreamService.Download:input_type -> google.protobuf.Empty
|
||||
1, // 1: testproto.StreamService.Download:output_type -> google.api.HttpBody
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
} |
||||
|
||||
func init() { file_proto_stream_proto_init() } |
||||
func file_proto_stream_proto_init() { |
||||
if File_proto_stream_proto != nil { |
||||
return |
||||
} |
||||
type x struct{} |
||||
out := protoimpl.TypeBuilder{ |
||||
File: protoimpl.DescBuilder{ |
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), |
||||
RawDescriptor: file_proto_stream_proto_rawDesc, |
||||
NumEnums: 0, |
||||
NumMessages: 0, |
||||
NumExtensions: 0, |
||||
NumServices: 1, |
||||
}, |
||||
GoTypes: file_proto_stream_proto_goTypes, |
||||
DependencyIndexes: file_proto_stream_proto_depIdxs, |
||||
}.Build() |
||||
File_proto_stream_proto = out.File |
||||
file_proto_stream_proto_rawDesc = nil |
||||
file_proto_stream_proto_goTypes = nil |
||||
file_proto_stream_proto_depIdxs = nil |
||||
} |
@ -0,0 +1,303 @@ |
||||
// Code generated by protoc-gen-go-http. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-http v2.0.0-rc3
|
||||
|
||||
package testproto |
||||
|
||||
import ( |
||||
context "context" |
||||
middleware "github.com/go-kratos/kratos/v2/middleware" |
||||
transport "github.com/go-kratos/kratos/v2/transport" |
||||
http "github.com/go-kratos/kratos/v2/transport/http" |
||||
binding "github.com/go-kratos/kratos/v2/transport/http/binding" |
||||
) |
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the kratos package it is being compiled against.
|
||||
var _ = new(context.Context) |
||||
var _ = new(middleware.Middleware) |
||||
var _ = new(transport.Transporter) |
||||
var _ = binding.BindVars |
||||
|
||||
const _ = http.SupportPackageIsVersion1 |
||||
|
||||
type EchoServiceHTTPServer interface { |
||||
Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) |
||||
EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) |
||||
EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) |
||||
EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) |
||||
EchoResponseBody(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) |
||||
} |
||||
|
||||
func RegisterEchoServiceHTTPServer(s *http.Server, srv EchoServiceHTTPServer) { |
||||
r := s.Route("/") |
||||
r.GET("/v1/example/echo/{id}/{num}", _EchoService_Echo0_HTTP_Handler(srv)) |
||||
r.GET("/v1/example/echo/{id}/{num}/{lang}", _EchoService_Echo1_HTTP_Handler(srv)) |
||||
r.GET("/v1/example/echo1/{id}/{line_num}/{status.note}", _EchoService_Echo2_HTTP_Handler(srv)) |
||||
r.GET("/v1/example/echo2/{no.note}", _EchoService_Echo3_HTTP_Handler(srv)) |
||||
r.POST("/v1/example/echo/{id}", _EchoService_Echo4_HTTP_Handler(srv)) |
||||
r.POST("/v1/example/echo_body", _EchoService_EchoBody0_HTTP_Handler(srv)) |
||||
r.POST("/v1/example/echo_response_body", _EchoService_EchoResponseBody0_HTTP_Handler(srv)) |
||||
r.DELETE("/v1/example/echo_delete/{id}/{num}", _EchoService_EchoDelete0_HTTP_Handler(srv)) |
||||
r.PATCH("/v1/example/echo_patch", _EchoService_EchoPatch0_HTTP_Handler(srv)) |
||||
} |
||||
|
||||
func _EchoService_Echo0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Context) error { |
||||
return func(ctx http.Context) error { |
||||
var in SimpleMessage |
||||
if err := ctx.Bind(&in); err != nil { |
||||
return err |
||||
} |
||||
if err := binding.BindVars(ctx.Vars(), &in); err != nil { |
||||
return err |
||||
} |
||||
transport.SetOperation(ctx, "/testproto.EchoService/Echo") |
||||
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.Echo(ctx, req.(*SimpleMessage)) |
||||
}) |
||||
out, err := h(ctx, &in) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
return ctx.Result(200, reply) |
||||
} |
||||
} |
||||
|
||||
func _EchoService_Echo1_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Context) error { |
||||
return func(ctx http.Context) error { |
||||
var in SimpleMessage |
||||
if err := ctx.Bind(&in); err != nil { |
||||
return err |
||||
} |
||||
if err := binding.BindVars(ctx.Vars(), &in); err != nil { |
||||
return err |
||||
} |
||||
transport.SetOperation(ctx, "/testproto.EchoService/Echo") |
||||
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.Echo(ctx, req.(*SimpleMessage)) |
||||
}) |
||||
out, err := h(ctx, &in) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
return ctx.Result(200, reply) |
||||
} |
||||
} |
||||
|
||||
func _EchoService_Echo2_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Context) error { |
||||
return func(ctx http.Context) error { |
||||
var in SimpleMessage |
||||
if err := ctx.Bind(&in); err != nil { |
||||
return err |
||||
} |
||||
if err := binding.BindVars(ctx.Vars(), &in); err != nil { |
||||
return err |
||||
} |
||||
transport.SetOperation(ctx, "/testproto.EchoService/Echo") |
||||
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.Echo(ctx, req.(*SimpleMessage)) |
||||
}) |
||||
out, err := h(ctx, &in) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
return ctx.Result(200, reply) |
||||
} |
||||
} |
||||
|
||||
func _EchoService_Echo3_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Context) error { |
||||
return func(ctx http.Context) error { |
||||
var in SimpleMessage |
||||
if err := ctx.Bind(&in); err != nil { |
||||
return err |
||||
} |
||||
if err := binding.BindVars(ctx.Vars(), &in); err != nil { |
||||
return err |
||||
} |
||||
transport.SetOperation(ctx, "/testproto.EchoService/Echo") |
||||
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.Echo(ctx, req.(*SimpleMessage)) |
||||
}) |
||||
out, err := h(ctx, &in) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
return ctx.Result(200, reply) |
||||
} |
||||
} |
||||
|
||||
func _EchoService_Echo4_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Context) error { |
||||
return func(ctx http.Context) error { |
||||
var in SimpleMessage |
||||
if err := ctx.Bind(&in); err != nil { |
||||
return err |
||||
} |
||||
if err := binding.BindVars(ctx.Vars(), &in); err != nil { |
||||
return err |
||||
} |
||||
transport.SetOperation(ctx, "/testproto.EchoService/Echo") |
||||
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.Echo(ctx, req.(*SimpleMessage)) |
||||
}) |
||||
out, err := h(ctx, &in) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
return ctx.Result(200, reply) |
||||
} |
||||
} |
||||
|
||||
func _EchoService_EchoBody0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Context) error { |
||||
return func(ctx http.Context) error { |
||||
var in SimpleMessage |
||||
if err := ctx.Bind(&in); err != nil { |
||||
return err |
||||
} |
||||
transport.SetOperation(ctx, "/testproto.EchoService/EchoBody") |
||||
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.EchoBody(ctx, req.(*SimpleMessage)) |
||||
}) |
||||
out, err := h(ctx, &in) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
return ctx.Result(200, reply) |
||||
} |
||||
} |
||||
|
||||
func _EchoService_EchoResponseBody0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Context) error { |
||||
return func(ctx http.Context) error { |
||||
var in DynamicMessageUpdate |
||||
if err := ctx.Bind(&in); err != nil { |
||||
return err |
||||
} |
||||
transport.SetOperation(ctx, "/testproto.EchoService/EchoResponseBody") |
||||
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.EchoResponseBody(ctx, req.(*DynamicMessageUpdate)) |
||||
}) |
||||
out, err := h(ctx, &in) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
reply := out.(*DynamicMessageUpdate) |
||||
return ctx.Result(200, reply.Body) |
||||
} |
||||
} |
||||
|
||||
func _EchoService_EchoDelete0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Context) error { |
||||
return func(ctx http.Context) error { |
||||
var in SimpleMessage |
||||
if err := ctx.Bind(&in); err != nil { |
||||
return err |
||||
} |
||||
if err := binding.BindVars(ctx.Vars(), &in); err != nil { |
||||
return err |
||||
} |
||||
transport.SetOperation(ctx, "/testproto.EchoService/EchoDelete") |
||||
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.EchoDelete(ctx, req.(*SimpleMessage)) |
||||
}) |
||||
out, err := h(ctx, &in) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
reply := out.(*SimpleMessage) |
||||
return ctx.Result(200, reply) |
||||
} |
||||
} |
||||
|
||||
func _EchoService_EchoPatch0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Context) error { |
||||
return func(ctx http.Context) error { |
||||
var in DynamicMessageUpdate |
||||
if err := ctx.Bind(&in.Body); err != nil { |
||||
return err |
||||
} |
||||
transport.SetOperation(ctx, "/testproto.EchoService/EchoPatch") |
||||
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.EchoPatch(ctx, req.(*DynamicMessageUpdate)) |
||||
}) |
||||
out, err := h(ctx, &in) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
reply := out.(*DynamicMessageUpdate) |
||||
return ctx.Result(200, reply) |
||||
} |
||||
} |
||||
|
||||
type EchoServiceHTTPClient interface { |
||||
Echo(ctx context.Context, req *SimpleMessage, opts ...http.CallOption) (rsp *SimpleMessage, err error) |
||||
EchoBody(ctx context.Context, req *SimpleMessage, opts ...http.CallOption) (rsp *SimpleMessage, err error) |
||||
EchoDelete(ctx context.Context, req *SimpleMessage, opts ...http.CallOption) (rsp *SimpleMessage, err error) |
||||
EchoPatch(ctx context.Context, req *DynamicMessageUpdate, opts ...http.CallOption) (rsp *DynamicMessageUpdate, err error) |
||||
EchoResponseBody(ctx context.Context, req *DynamicMessageUpdate, opts ...http.CallOption) (rsp *DynamicMessageUpdate, err error) |
||||
} |
||||
|
||||
type EchoServiceHTTPClientImpl struct { |
||||
cc *http.Client |
||||
} |
||||
|
||||
func NewEchoServiceHTTPClient(client *http.Client) EchoServiceHTTPClient { |
||||
return &EchoServiceHTTPClientImpl{client} |
||||
} |
||||
|
||||
func (c *EchoServiceHTTPClientImpl) Echo(ctx context.Context, in *SimpleMessage, opts ...http.CallOption) (*SimpleMessage, error) { |
||||
var out SimpleMessage |
||||
path := binding.EncodeVars("/v1/example/echo/{id}", in, false) |
||||
opts = append(opts, http.Operation("/testproto.EchoService/Echo")) |
||||
err := c.cc.Invoke(ctx, "POST", path, nil, &out, opts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &out, err |
||||
} |
||||
|
||||
func (c *EchoServiceHTTPClientImpl) EchoBody(ctx context.Context, in *SimpleMessage, opts ...http.CallOption) (*SimpleMessage, error) { |
||||
var out SimpleMessage |
||||
path := binding.EncodeVars("/v1/example/echo_body", in, false) |
||||
opts = append(opts, http.Operation("/testproto.EchoService/EchoBody")) |
||||
err := c.cc.Invoke(ctx, "POST", path, in, &out, opts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &out, err |
||||
} |
||||
|
||||
func (c *EchoServiceHTTPClientImpl) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...http.CallOption) (*SimpleMessage, error) { |
||||
var out SimpleMessage |
||||
path := binding.EncodeVars("/v1/example/echo_delete/{id}/{num}", in, false) |
||||
opts = append(opts, http.Operation("/testproto.EchoService/EchoDelete")) |
||||
err := c.cc.Invoke(ctx, "DELETE", path, nil, &out, opts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &out, err |
||||
} |
||||
|
||||
func (c *EchoServiceHTTPClientImpl) EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...http.CallOption) (*DynamicMessageUpdate, error) { |
||||
var out DynamicMessageUpdate |
||||
path := binding.EncodeVars("/v1/example/echo_patch", in, false) |
||||
opts = append(opts, http.Operation("/testproto.EchoService/EchoPatch")) |
||||
err := c.cc.Invoke(ctx, "PATCH", path, in.Body, &out, opts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &out, err |
||||
} |
||||
|
||||
func (c *EchoServiceHTTPClientImpl) EchoResponseBody(ctx context.Context, in *DynamicMessageUpdate, opts ...http.CallOption) (*DynamicMessageUpdate, error) { |
||||
var out DynamicMessageUpdate |
||||
path := binding.EncodeVars("/v1/example/echo_response_body", in, false) |
||||
opts = append(opts, http.Operation("/testproto.EchoService/EchoResponseBody")) |
||||
err := c.cc.Invoke(ctx, "POST", path, in, &out.Body, opts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &out, err |
||||
} |
@ -0,0 +1,3 @@ |
||||
package testproto |
||||
|
||||
//go:generate protoc --proto_path=. --proto_path=../../third_party --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. --go-http_out=paths=source_relative:. echo_service.proto stream.proto
|
@ -0,0 +1,86 @@ |
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.15.7
|
||||
// source: stream.proto
|
||||
|
||||
package testproto |
||||
|
||||
import ( |
||||
_ "google.golang.org/genproto/googleapis/api/annotations" |
||||
httpbody "google.golang.org/genproto/googleapis/api/httpbody" |
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect" |
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl" |
||||
emptypb "google.golang.org/protobuf/types/known/emptypb" |
||||
reflect "reflect" |
||||
) |
||||
|
||||
const ( |
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) |
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) |
||||
) |
||||
|
||||
var File_stream_proto protoreflect.FileDescriptor |
||||
|
||||
var file_stream_proto_rawDesc = []byte{ |
||||
0x0a, 0x0c, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, |
||||
0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, |
||||
0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, |
||||
0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, |
||||
0x61, 0x70, 0x69, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x70, 0x72, 0x6f, |
||||
0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, |
||||
0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, |
||||
0x69, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, |
||||
0x12, 0x58, 0x0a, 0x08, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x16, 0x2e, 0x67, |
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, |
||||
0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, |
||||
0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, |
||||
0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, |
||||
0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x30, 0x01, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, |
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, |
||||
0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, |
||||
0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, |
||||
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, |
||||
0x6f, 0x74, 0x6f, 0x3b, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, |
||||
0x72, 0x6f, 0x74, 0x6f, 0x33, |
||||
} |
||||
|
||||
var file_stream_proto_goTypes = []interface{}{ |
||||
(*emptypb.Empty)(nil), // 0: google.protobuf.Empty
|
||||
(*httpbody.HttpBody)(nil), // 1: google.api.HttpBody
|
||||
} |
||||
var file_stream_proto_depIdxs = []int32{ |
||||
0, // 0: testproto.StreamService.Download:input_type -> google.protobuf.Empty
|
||||
1, // 1: testproto.StreamService.Download:output_type -> google.api.HttpBody
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
} |
||||
|
||||
func init() { file_stream_proto_init() } |
||||
func file_stream_proto_init() { |
||||
if File_stream_proto != nil { |
||||
return |
||||
} |
||||
type x struct{} |
||||
out := protoimpl.TypeBuilder{ |
||||
File: protoimpl.DescBuilder{ |
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), |
||||
RawDescriptor: file_stream_proto_rawDesc, |
||||
NumEnums: 0, |
||||
NumMessages: 0, |
||||
NumExtensions: 0, |
||||
NumServices: 1, |
||||
}, |
||||
GoTypes: file_stream_proto_goTypes, |
||||
DependencyIndexes: file_stream_proto_depIdxs, |
||||
}.Build() |
||||
File_stream_proto = out.File |
||||
file_stream_proto_rawDesc = nil |
||||
file_stream_proto_goTypes = nil |
||||
file_stream_proto_depIdxs = nil |
||||
} |
@ -0,0 +1,89 @@ |
||||
package http |
||||
|
||||
import ( |
||||
"io/ioutil" |
||||
"net/http" |
||||
|
||||
"github.com/go-kratos/kratos/v2/encoding" |
||||
"github.com/go-kratos/kratos/v2/errors" |
||||
"github.com/go-kratos/kratos/v2/internal/httputil" |
||||
"github.com/go-kratos/kratos/v2/transport/http/binding" |
||||
) |
||||
|
||||
// SupportPackageIsVersion1 These constants should not be referenced from any other code.
|
||||
const SupportPackageIsVersion1 = true |
||||
|
||||
// DecodeRequestFunc is decode request func.
|
||||
type DecodeRequestFunc func(*http.Request, interface{}) error |
||||
|
||||
// EncodeResponseFunc is encode response func.
|
||||
type EncodeResponseFunc func(http.ResponseWriter, *http.Request, interface{}) error |
||||
|
||||
// EncodeErrorFunc is encode error func.
|
||||
type EncodeErrorFunc func(http.ResponseWriter, *http.Request, error) |
||||
|
||||
// DefaultRequestDecoder decodes the request body to object.
|
||||
func DefaultRequestDecoder(r *http.Request, v interface{}) error { |
||||
codec, ok := CodecForRequest(r, "Content-Type") |
||||
if ok { |
||||
data, err := ioutil.ReadAll(r.Body) |
||||
if err != nil { |
||||
return errors.BadRequest("CODEC", err.Error()) |
||||
} |
||||
if err := codec.Unmarshal(data, v); err != nil { |
||||
return errors.BadRequest("CODEC", err.Error()) |
||||
} |
||||
} else { |
||||
if err := binding.BindForm(r, v); err != nil { |
||||
return errors.BadRequest("CODEC", err.Error()) |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// DefaultResponseEncoder encodes the object to the HTTP response.
|
||||
func DefaultResponseEncoder(w http.ResponseWriter, r *http.Request, v interface{}) error { |
||||
codec, _ := CodecForRequest(r, "Accept") |
||||
data, err := codec.Marshal(v) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
w.Header().Set("Content-Type", httputil.ContentType(codec.Name())) |
||||
if sc, ok := v.(interface { |
||||
StatusCode() int |
||||
}); ok { |
||||
w.WriteHeader(sc.StatusCode()) |
||||
} |
||||
_, _ = w.Write(data) |
||||
return nil |
||||
} |
||||
|
||||
// DefaultErrorEncoder encodes the error to the HTTP response.
|
||||
func DefaultErrorEncoder(w http.ResponseWriter, r *http.Request, se error) { |
||||
codec, _ := CodecForRequest(r, "Accept") |
||||
body, err := codec.Marshal(se) |
||||
if err != nil { |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
w.Header().Set("Content-Type", httputil.ContentType(codec.Name())) |
||||
if sc, ok := se.(interface { |
||||
StatusCode() int |
||||
}); ok { |
||||
w.WriteHeader(sc.StatusCode()) |
||||
} else { |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
} |
||||
w.Write(body) |
||||
} |
||||
|
||||
// CodecForRequest get encoding.Codec via http.Request
|
||||
func CodecForRequest(r *http.Request, name string) (encoding.Codec, bool) { |
||||
for _, accept := range r.Header[name] { |
||||
codec := encoding.GetCodec(httputil.ContentSubtype(accept)) |
||||
if codec != nil { |
||||
return codec, true |
||||
} |
||||
} |
||||
return encoding.GetCodec("json"), false |
||||
} |
@ -0,0 +1,142 @@ |
||||
package http |
||||
|
||||
import ( |
||||
"context" |
||||
"encoding/json" |
||||
"encoding/xml" |
||||
"io" |
||||
"net/http" |
||||
"net/url" |
||||
"time" |
||||
|
||||
"github.com/go-kratos/kratos/v2/middleware" |
||||
"github.com/gorilla/mux" |
||||
) |
||||
|
||||
var _ Context = (*wrapper)(nil) |
||||
|
||||
// HandlerFunc defines a function to serve HTTP requests.
|
||||
type HandlerFunc func(Context) error |
||||
|
||||
// Context is an HTTP Context.
|
||||
type Context interface { |
||||
context.Context |
||||
Vars() url.Values |
||||
Form() url.Values |
||||
Header() http.Header |
||||
Request() *http.Request |
||||
Response() http.ResponseWriter |
||||
Middleware(middleware.Handler) middleware.Handler |
||||
Bind(interface{}) error |
||||
Returns(interface{}, error) error |
||||
Result(int, interface{}) error |
||||
JSON(int, interface{}) error |
||||
XML(int, interface{}) error |
||||
String(int, string) error |
||||
Blob(int, string, []byte) error |
||||
Stream(int, string, io.Reader) error |
||||
Reset(http.ResponseWriter, *http.Request) |
||||
} |
||||
|
||||
type wrapper struct { |
||||
route *Route |
||||
req *http.Request |
||||
res http.ResponseWriter |
||||
} |
||||
|
||||
func (c *wrapper) Header() http.Header { |
||||
return c.req.Header |
||||
} |
||||
|
||||
func (c *wrapper) Vars() url.Values { |
||||
raws := mux.Vars(c.req) |
||||
vars := make(url.Values, len(raws)) |
||||
for k, v := range raws { |
||||
vars[k] = []string{v} |
||||
} |
||||
return vars |
||||
} |
||||
func (c *wrapper) Form() url.Values { |
||||
if err := c.req.ParseForm(); err != nil { |
||||
return url.Values{} |
||||
} |
||||
return c.req.Form |
||||
} |
||||
func (c *wrapper) Request() *http.Request { return c.req } |
||||
func (c *wrapper) Response() http.ResponseWriter { return c.res } |
||||
func (c *wrapper) Middleware(h middleware.Handler) middleware.Handler { |
||||
return middleware.Chain(c.route.srv.ms...)(h) |
||||
} |
||||
func (c *wrapper) Bind(v interface{}) error { return c.route.srv.dec(c.req, v) } |
||||
func (c *wrapper) Returns(v interface{}, err error) error { |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if err := c.route.srv.enc(c.res, c.req, v); err != nil { |
||||
return err |
||||
} |
||||
return nil |
||||
} |
||||
func (c *wrapper) Result(code int, v interface{}) error { |
||||
c.res.WriteHeader(code) |
||||
if err := c.route.srv.enc(c.res, c.req, v); err != nil { |
||||
return err |
||||
} |
||||
return nil |
||||
} |
||||
func (c *wrapper) JSON(code int, v interface{}) error { |
||||
c.res.WriteHeader(code) |
||||
c.res.Header().Set("Content-Type", "application/json") |
||||
return json.NewEncoder(c.res).Encode(v) |
||||
} |
||||
func (c *wrapper) XML(code int, v interface{}) error { |
||||
c.res.WriteHeader(code) |
||||
c.res.Header().Set("Content-Type", "application/xml") |
||||
return xml.NewEncoder(c.res).Encode(v) |
||||
} |
||||
func (c *wrapper) String(code int, text string) error { |
||||
c.res.WriteHeader(code) |
||||
c.res.Header().Set("Content-Type", "text/plain") |
||||
c.res.Write([]byte(text)) |
||||
return nil |
||||
} |
||||
func (c *wrapper) Blob(code int, contentType string, data []byte) error { |
||||
c.res.WriteHeader(code) |
||||
c.res.Header().Set("Content-Type", contentType) |
||||
c.res.Write(data) |
||||
return nil |
||||
} |
||||
func (c *wrapper) Stream(code int, contentType string, rd io.Reader) error { |
||||
c.res.WriteHeader(code) |
||||
c.res.Header().Set("Content-Type", contentType) |
||||
_, err := io.Copy(c.res, rd) |
||||
return err |
||||
} |
||||
func (c *wrapper) Reset(res http.ResponseWriter, req *http.Request) { |
||||
c.res = res |
||||
c.req = req |
||||
} |
||||
func (c *wrapper) Deadline() (time.Time, bool) { |
||||
if c.req == nil { |
||||
return time.Time{}, false |
||||
} |
||||
return c.req.Context().Deadline() |
||||
} |
||||
func (c *wrapper) Done() <-chan struct{} { |
||||
if c.req == nil { |
||||
return nil |
||||
} |
||||
return c.req.Context().Done() |
||||
} |
||||
func (c *wrapper) Err() error { |
||||
if c.req == nil { |
||||
return context.Canceled |
||||
} |
||||
return c.req.Context().Err() |
||||
} |
||||
func (c *wrapper) Value(key interface{}) interface{} { |
||||
if c.req == nil { |
||||
return nil |
||||
} |
||||
return c.req.Context().Value(key) |
||||
} |
@ -1,215 +0,0 @@ |
||||
package http |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"io/ioutil" |
||||
"net/http" |
||||
"reflect" |
||||
|
||||
"github.com/go-kratos/kratos/v2/encoding" |
||||
"github.com/go-kratos/kratos/v2/errors" |
||||
"github.com/go-kratos/kratos/v2/internal/httputil" |
||||
"github.com/go-kratos/kratos/v2/middleware" |
||||
"github.com/go-kratos/kratos/v2/transport/http/binding" |
||||
) |
||||
|
||||
// SupportPackageIsVersion1 These constants should not be referenced from any other code.
|
||||
const SupportPackageIsVersion1 = true |
||||
|
||||
// DecodeRequestFunc is decode request func.
|
||||
type DecodeRequestFunc func(*http.Request, interface{}) error |
||||
|
||||
// EncodeResponseFunc is encode response func.
|
||||
type EncodeResponseFunc func(http.ResponseWriter, *http.Request, interface{}) error |
||||
|
||||
// EncodeErrorFunc is encode error func.
|
||||
type EncodeErrorFunc func(http.ResponseWriter, *http.Request, error) |
||||
|
||||
// HandleOption is handle option.
|
||||
type HandleOption func(*HandleOptions) |
||||
|
||||
// HandleOptions is handle options.
|
||||
// Deprecated: use Handler instead.
|
||||
type HandleOptions struct { |
||||
Decode DecodeRequestFunc |
||||
Encode EncodeResponseFunc |
||||
Error EncodeErrorFunc |
||||
Middleware middleware.Middleware |
||||
} |
||||
|
||||
// DefaultHandleOptions returns a default handle options.
|
||||
// Deprecated: use NewHandler instead.
|
||||
func DefaultHandleOptions() HandleOptions { |
||||
return HandleOptions{ |
||||
Decode: DefaultRequestDecoder, |
||||
Encode: DefaultResponseEncoder, |
||||
Error: DefaultErrorEncoder, |
||||
} |
||||
} |
||||
|
||||
// RequestDecoder with request decoder.
|
||||
func RequestDecoder(dec DecodeRequestFunc) HandleOption { |
||||
return func(o *HandleOptions) { |
||||
o.Decode = dec |
||||
} |
||||
} |
||||
|
||||
// ResponseEncoder with response encoder.
|
||||
func ResponseEncoder(en EncodeResponseFunc) HandleOption { |
||||
return func(o *HandleOptions) { |
||||
o.Encode = en |
||||
} |
||||
} |
||||
|
||||
// ErrorEncoder with error encoder.
|
||||
func ErrorEncoder(en EncodeErrorFunc) HandleOption { |
||||
return func(o *HandleOptions) { |
||||
o.Error = en |
||||
} |
||||
} |
||||
|
||||
// Middleware with middleware option.
|
||||
func Middleware(m ...middleware.Middleware) HandleOption { |
||||
return func(o *HandleOptions) { |
||||
o.Middleware = middleware.Chain(m...) |
||||
} |
||||
} |
||||
|
||||
// Handler is handle options.
|
||||
type Handler struct { |
||||
method reflect.Value |
||||
in reflect.Type |
||||
out reflect.Type |
||||
opts HandleOptions |
||||
} |
||||
|
||||
// NewHandler new an HTTP handler.
|
||||
func NewHandler(handler interface{}, opts ...HandleOption) http.Handler { |
||||
if err := validateHandler(handler); err != nil { |
||||
panic(err) |
||||
} |
||||
typ := reflect.TypeOf(handler) |
||||
h := &Handler{ |
||||
method: reflect.ValueOf(handler), |
||||
in: typ.In(1).Elem(), |
||||
out: typ.Out(0).Elem(), |
||||
opts: DefaultHandleOptions(), |
||||
} |
||||
for _, o := range opts { |
||||
o(&h.opts) |
||||
} |
||||
return h |
||||
} |
||||
|
||||
func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
||||
in := reflect.New(h.in).Interface() |
||||
if err := h.opts.Decode(req, in); err != nil { |
||||
h.opts.Error(w, req, err) |
||||
return |
||||
} |
||||
invoke := func(ctx context.Context, in interface{}) (interface{}, error) { |
||||
ret := h.method.Call([]reflect.Value{ |
||||
reflect.ValueOf(ctx), |
||||
reflect.ValueOf(in), |
||||
}) |
||||
if ret[1].IsNil() { |
||||
return ret[0].Interface(), nil |
||||
} |
||||
return nil, ret[1].Interface().(error) |
||||
} |
||||
if h.opts.Middleware != nil { |
||||
invoke = h.opts.Middleware(invoke) |
||||
} |
||||
out, err := invoke(req.Context(), in) |
||||
if err != nil { |
||||
h.opts.Error(w, req, err) |
||||
return |
||||
} |
||||
if err := h.opts.Encode(w, req, out); err != nil { |
||||
h.opts.Error(w, req, err) |
||||
} |
||||
} |
||||
|
||||
func validateHandler(handler interface{}) error { |
||||
typ := reflect.TypeOf(handler) |
||||
if typ.NumIn() != 2 || typ.NumOut() != 2 { |
||||
return fmt.Errorf("invalid types, in: %d out: %d", typ.NumIn(), typ.NumOut()) |
||||
} |
||||
if typ.In(1).Kind() != reflect.Ptr || typ.Out(0).Kind() != reflect.Ptr { |
||||
return fmt.Errorf("invalid types is not a pointer") |
||||
} |
||||
if !typ.In(0).Implements(reflect.TypeOf((*context.Context)(nil)).Elem()) { |
||||
return fmt.Errorf("input does not implement the context") |
||||
} |
||||
if !typ.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) { |
||||
return fmt.Errorf("input does not implement the error") |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// DefaultRequestDecoder decodes the request body to object.
|
||||
func DefaultRequestDecoder(r *http.Request, v interface{}) error { |
||||
codec, ok := CodecForRequest(r, "Content-Type") |
||||
if ok { |
||||
data, err := ioutil.ReadAll(r.Body) |
||||
if err != nil { |
||||
return errors.BadRequest("CODEC", err.Error()) |
||||
} |
||||
if err := codec.Unmarshal(data, v); err != nil { |
||||
return errors.BadRequest("CODEC", err.Error()) |
||||
} |
||||
} else { |
||||
if err := binding.BindForm(r, v); err != nil { |
||||
return errors.BadRequest("CODEC", err.Error()) |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// DefaultResponseEncoder encodes the object to the HTTP response.
|
||||
func DefaultResponseEncoder(w http.ResponseWriter, r *http.Request, v interface{}) error { |
||||
codec, _ := CodecForRequest(r, "Accept") |
||||
data, err := codec.Marshal(v) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
w.Header().Set("Content-Type", httputil.ContentType(codec.Name())) |
||||
if sc, ok := v.(interface { |
||||
StatusCode() int |
||||
}); ok { |
||||
w.WriteHeader(sc.StatusCode()) |
||||
} |
||||
_, _ = w.Write(data) |
||||
return nil |
||||
} |
||||
|
||||
// DefaultErrorEncoder encodes the error to the HTTP response.
|
||||
func DefaultErrorEncoder(w http.ResponseWriter, r *http.Request, se error) { |
||||
codec, _ := CodecForRequest(r, "Accept") |
||||
body, err := codec.Marshal(se) |
||||
if err != nil { |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
w.Header().Set("Content-Type", httputil.ContentType(codec.Name())) |
||||
if sc, ok := se.(interface { |
||||
StatusCode() int |
||||
}); ok { |
||||
w.WriteHeader(sc.StatusCode()) |
||||
} else { |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
} |
||||
w.Write(body) |
||||
} |
||||
|
||||
// CodecForRequest get encoding.Codec via http.Request
|
||||
func CodecForRequest(r *http.Request, name string) (encoding.Codec, bool) { |
||||
for _, accept := range r.Header[name] { |
||||
codec := encoding.GetCodec(httputil.ContentSubtype(accept)) |
||||
if codec != nil { |
||||
return codec, true |
||||
} |
||||
} |
||||
return encoding.GetCodec("json"), false |
||||
} |
@ -1,24 +0,0 @@ |
||||
package http |
||||
|
||||
import ( |
||||
"context" |
||||
"testing" |
||||
) |
||||
|
||||
type HelloRequest struct { |
||||
Name string `json:"name"` |
||||
} |
||||
type HelloReply struct { |
||||
Message string `json:"message"` |
||||
} |
||||
type GreeterService struct { |
||||
} |
||||
|
||||
func (s *GreeterService) SayHello(ctx context.Context, req *HelloRequest) (*HelloReply, error) { |
||||
return &HelloReply{Message: "hello " + req.Name}, nil |
||||
} |
||||
|
||||
func TestHandler(t *testing.T) { |
||||
s := &GreeterService{} |
||||
_ = NewHandler(s.SayHello) |
||||
} |
@ -0,0 +1,101 @@ |
||||
package http |
||||
|
||||
import ( |
||||
"net/http" |
||||
"path" |
||||
"sync" |
||||
) |
||||
|
||||
// FilterFunc is a function which receives an http.Handler and returns another http.Handler.
|
||||
type FilterFunc func(http.Handler) http.Handler |
||||
|
||||
// FilterChain returns a FilterFunc that specifies the chained handler for HTTP Router.
|
||||
func FilterChain(filters ...FilterFunc) FilterFunc { |
||||
return func(next http.Handler) http.Handler { |
||||
for i := len(filters) - 1; i >= 0; i-- { |
||||
next = filters[i](next) |
||||
} |
||||
return next |
||||
} |
||||
} |
||||
|
||||
// Route is an HTTP route.
|
||||
type Route struct { |
||||
prefix string |
||||
pool sync.Pool |
||||
srv *Server |
||||
filters []FilterFunc |
||||
} |
||||
|
||||
func newRoute(prefix string, srv *Server, filters ...FilterFunc) *Route { |
||||
r := &Route{ |
||||
prefix: prefix, |
||||
srv: srv, |
||||
filters: filters, |
||||
} |
||||
r.pool.New = func() interface{} { |
||||
return &wrapper{route: r} |
||||
} |
||||
return r |
||||
} |
||||
|
||||
// Handle registers a new route with a matcher for the URL path and method.
|
||||
func (r *Route) Handle(method, relativePath string, h HandlerFunc, filters ...FilterFunc) { |
||||
next := http.Handler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { |
||||
ctx := r.pool.Get().(Context) |
||||
ctx.Reset(res, req) |
||||
if err := h(ctx); err != nil { |
||||
r.srv.ene(res, req, err) |
||||
} |
||||
ctx.Reset(nil, nil) |
||||
r.pool.Put(ctx) |
||||
})) |
||||
next = FilterChain(filters...)(next) |
||||
next = FilterChain(r.filters...)(next) |
||||
r.srv.router.Handle(path.Join(r.prefix, relativePath), next).Methods(method) |
||||
} |
||||
|
||||
// GET registers a new GET route for a path with matching handler in the router.
|
||||
func (r *Route) GET(path string, h HandlerFunc, m ...FilterFunc) { |
||||
r.Handle(http.MethodGet, path, h, m...) |
||||
} |
||||
|
||||
// HEAD registers a new HEAD route for a path with matching handler in the router.
|
||||
func (r *Route) HEAD(path string, h HandlerFunc, m ...FilterFunc) { |
||||
r.Handle(http.MethodHead, path, h, m...) |
||||
} |
||||
|
||||
// POST registers a new POST route for a path with matching handler in the router.
|
||||
func (r *Route) POST(path string, h HandlerFunc, m ...FilterFunc) { |
||||
r.Handle(http.MethodPost, path, h, m...) |
||||
} |
||||
|
||||
// PUT registers a new PUT route for a path with matching handler in the router.
|
||||
func (r *Route) PUT(path string, h HandlerFunc, m ...FilterFunc) { |
||||
r.Handle(http.MethodPut, path, h, m...) |
||||
} |
||||
|
||||
// PATCH registers a new PATCH route for a path with matching handler in the router.
|
||||
func (r *Route) PATCH(path string, h HandlerFunc, m ...FilterFunc) { |
||||
r.Handle(http.MethodPatch, path, h, m...) |
||||
} |
||||
|
||||
// DELETE registers a new DELETE route for a path with matching handler in the router.
|
||||
func (r *Route) DELETE(path string, h HandlerFunc, m ...FilterFunc) { |
||||
r.Handle(http.MethodDelete, path, h, m...) |
||||
} |
||||
|
||||
// CONNECT registers a new CONNECT route for a path with matching handler in the router.
|
||||
func (r *Route) CONNECT(path string, h HandlerFunc, m ...FilterFunc) { |
||||
r.Handle(http.MethodConnect, path, h, m...) |
||||
} |
||||
|
||||
// OPTIONS registers a new OPTIONS route for a path with matching handler in the router.
|
||||
func (r *Route) OPTIONS(path string, h HandlerFunc, m ...FilterFunc) { |
||||
r.Handle(http.MethodOptions, path, h, m...) |
||||
} |
||||
|
||||
// TRACE registers a new TRACE route for a path with matching handler in the router.
|
||||
func (r *Route) TRACE(path string, h HandlerFunc, m ...FilterFunc) { |
||||
r.Handle(http.MethodTrace, path, h, m...) |
||||
} |
@ -0,0 +1,135 @@ |
||||
package http |
||||
|
||||
import ( |
||||
"context" |
||||
"encoding/json" |
||||
"fmt" |
||||
"log" |
||||
"net/http" |
||||
"strings" |
||||
"testing" |
||||
"time" |
||||
|
||||
"github.com/go-kratos/kratos/v2/internal/host" |
||||
) |
||||
|
||||
type User struct { |
||||
Name string `json:"name"` |
||||
} |
||||
|
||||
func authFilter(next http.Handler) http.Handler { |
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
||||
// Do stuff here
|
||||
log.Println("auth:", r.Method, r.RequestURI) |
||||
// Call the next handler, which can be another middleware in the chain, or the final handler.
|
||||
next.ServeHTTP(w, r) |
||||
}) |
||||
} |
||||
func loggingFilter(next http.Handler) http.Handler { |
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
||||
// Do stuff here
|
||||
log.Println("logging:", r.Method, r.RequestURI) |
||||
// Call the next handler, which can be another middleware in the chain, or the final handler.
|
||||
next.ServeHTTP(w, r) |
||||
}) |
||||
} |
||||
|
||||
func TestRoute(t *testing.T) { |
||||
ctx := context.Background() |
||||
srv := NewServer( |
||||
Filter(loggingFilter), |
||||
) |
||||
route := srv.Route("/v1") |
||||
route.GET("/users/{name}", func(ctx Context) error { |
||||
u := new(User) |
||||
u.Name = ctx.Vars().Get("name") |
||||
return ctx.Result(200, u) |
||||
}, authFilter) |
||||
route.POST("/users", func(ctx Context) error { |
||||
u := new(User) |
||||
if err := ctx.Bind(u); err != nil { |
||||
return err |
||||
} |
||||
return ctx.Result(201, u) |
||||
}) |
||||
route.PUT("/users", func(ctx Context) error { |
||||
u := new(User) |
||||
if err := ctx.Bind(u); err != nil { |
||||
return err |
||||
} |
||||
h := ctx.Middleware(func(ctx context.Context, in interface{}) (interface{}, error) { |
||||
return u, nil |
||||
}) |
||||
return ctx.Returns(h(ctx, u)) |
||||
}) |
||||
|
||||
if e, err := srv.Endpoint(); err != nil || e == nil { |
||||
t.Fatal(e, err) |
||||
} |
||||
go func() { |
||||
if err := srv.Start(ctx); err != nil { |
||||
panic(err) |
||||
} |
||||
}() |
||||
time.Sleep(time.Second) |
||||
testRoute(t, srv) |
||||
srv.Stop(ctx) |
||||
} |
||||
|
||||
func testRoute(t *testing.T, srv *Server) { |
||||
port, ok := host.Port(srv.lis) |
||||
if !ok { |
||||
t.Fatalf("extract port error: %v", srv.lis) |
||||
} |
||||
base := fmt.Sprintf("http://127.0.0.1:%d/v1", port) |
||||
// GET
|
||||
resp, err := http.Get(base + "/users/foo") |
||||
if err != nil { |
||||
t.Fatal(err) |
||||
} |
||||
defer resp.Body.Close() |
||||
if resp.StatusCode != 200 { |
||||
t.Fatalf("code: %d", resp.StatusCode) |
||||
} |
||||
u := new(User) |
||||
if err := json.NewDecoder(resp.Body).Decode(u); err != nil { |
||||
t.Fatal(err) |
||||
} |
||||
if u.Name != "foo" { |
||||
t.Fatalf("got %s want foo", u.Name) |
||||
} |
||||
// POST
|
||||
resp, err = http.Post(base+"/users", "application/json", strings.NewReader(`{"name":"bar"}`)) |
||||
if err != nil { |
||||
t.Fatal(err) |
||||
} |
||||
defer resp.Body.Close() |
||||
if resp.StatusCode != 201 { |
||||
t.Fatalf("code: %d", resp.StatusCode) |
||||
} |
||||
u = new(User) |
||||
if err = json.NewDecoder(resp.Body).Decode(u); err != nil { |
||||
t.Fatal(err) |
||||
} |
||||
if u.Name != "bar" { |
||||
t.Fatalf("got %s want bar", u.Name) |
||||
} |
||||
// PUT
|
||||
req, _ := http.NewRequest("PUT", base+"/users", strings.NewReader(`{"name":"bar"}`)) |
||||
req.Header.Set("Content-Type", "application/json") |
||||
resp, err = http.DefaultClient.Do(req) |
||||
if err != nil { |
||||
t.Fatal(err) |
||||
} |
||||
defer resp.Body.Close() |
||||
if resp.StatusCode != 200 { |
||||
t.Fatalf("code: %d", resp.StatusCode) |
||||
} |
||||
u = new(User) |
||||
if err = json.NewDecoder(resp.Body).Decode(u); err != nil { |
||||
t.Fatal(err) |
||||
} |
||||
if u.Name != "bar" { |
||||
t.Fatalf("got %s want bar", u.Name) |
||||
} |
||||
} |
Loading…
Reference in new issue