dubbo.apache.org/dubbo-go/v3@v3.1.1/protocol/rest/server/rest_server.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package server 19 20 import ( 21 "context" 22 "errors" 23 "net/http" 24 "reflect" 25 "strconv" 26 ) 27 28 import ( 29 "github.com/dubbogo/gost/log/logger" 30 31 perrors "github.com/pkg/errors" 32 ) 33 34 import ( 35 "dubbo.apache.org/dubbo-go/v3/common" 36 "dubbo.apache.org/dubbo-go/v3/protocol" 37 "dubbo.apache.org/dubbo-go/v3/protocol/invocation" 38 rest_config "dubbo.apache.org/dubbo-go/v3/protocol/rest/config" 39 ) 40 41 const parseParameterErrorStr = "An error occurred while parsing parameters on the server" 42 43 // RestServer user can implement this server interface 44 type RestServer interface { 45 // Start rest server 46 Start(url *common.URL) 47 // Deploy a http api 48 Deploy(restMethodConfig *rest_config.RestMethodConfig, routeFunc func(request RestServerRequest, response RestServerResponse)) 49 // UnDeploy a http api 50 UnDeploy(restMethodConfig *rest_config.RestMethodConfig) 51 // Destroy rest server 52 Destroy() 53 } 54 55 // RestServerRequest interface 56 type RestServerRequest interface { 57 // RawRequest get the Ptr of http.Request 58 RawRequest() *http.Request 59 // PathParameter get the path parameter by name 60 PathParameter(name string) string 61 // PathParameters get the map of the path parameters 62 PathParameters() map[string]string 63 // QueryParameter get the query parameter by name 64 QueryParameter(name string) string 65 // QueryParameters get the map of query parameters 66 QueryParameters(name string) []string 67 // BodyParameter get the body parameter of name 68 BodyParameter(name string) (string, error) 69 // HeaderParameter get the header parameter of name 70 HeaderParameter(name string) string 71 // ReadEntity checks the Accept header and reads the content into the entityPointer. 72 ReadEntity(entityPointer interface{}) error 73 } 74 75 // RestServerResponse interface 76 type RestServerResponse interface { 77 http.ResponseWriter 78 // WriteError writes the http status and the error string on the response. err can be nil. 79 // Return an error if writing was not successful. 80 WriteError(httpStatus int, err error) (writeErr error) 81 // WriteEntity marshals the value using the representation denoted by the Accept Header. 82 WriteEntity(value interface{}) error 83 } 84 85 // GetRouteFunc is a route function will be invoked by http server 86 func GetRouteFunc(invoker protocol.Invoker, methodConfig *rest_config.RestMethodConfig) func(req RestServerRequest, resp RestServerResponse) { 87 return func(req RestServerRequest, resp RestServerResponse) { 88 var ( 89 err error 90 args []interface{} 91 ) 92 svc := common.ServiceMap.GetServiceByServiceKey(invoker.GetURL().Protocol, invoker.GetURL().ServiceKey()) 93 // get method 94 method := svc.Method()[methodConfig.MethodName] 95 argsTypes := method.ArgsType() 96 replyType := method.ReplyType() 97 // two ways to prepare arguments 98 // if method like this 'func1(req []interface{}, rsp *User) error' 99 // we don't have arguments type 100 if (len(argsTypes) == 1 || len(argsTypes) == 2 && replyType == nil) && 101 argsTypes[0].String() == "[]interface {}" { 102 args, err = getArgsInterfaceFromRequest(req, methodConfig) 103 } else { 104 args, err = getArgsFromRequest(req, argsTypes, methodConfig) 105 } 106 if err != nil { 107 logger.Errorf("[Go Restful] parsing http parameters error:%v", err) 108 err = resp.WriteError(http.StatusInternalServerError, errors.New(parseParameterErrorStr)) 109 if err != nil { 110 logger.Errorf("[Go Restful] WriteErrorString error:%v", err) 111 } 112 } 113 result := invoker.Invoke(context.Background(), invocation.NewRPCInvocation(methodConfig.MethodName, args, make(map[string]interface{}))) 114 if result.Error() != nil { 115 err = resp.WriteError(http.StatusInternalServerError, result.Error()) 116 if err != nil { 117 logger.Errorf("[Go Restful] WriteError error:%v", err) 118 } 119 return 120 } 121 err = resp.WriteEntity(result.Result()) 122 if err != nil { 123 logger.Errorf("[Go Restful] WriteEntity error:%v", err) 124 } 125 } 126 } 127 128 // getArgsInterfaceFromRequest when service function like GetUser(req []interface{}, rsp *User) error 129 // use this method to get arguments 130 func getArgsInterfaceFromRequest(req RestServerRequest, methodConfig *rest_config.RestMethodConfig) ([]interface{}, error) { 131 argsMap := make(map[int]interface{}, 8) 132 maxKey := 0 133 for k, v := range methodConfig.PathParamsMap { 134 if maxKey < k { 135 maxKey = k 136 } 137 argsMap[k] = req.PathParameter(v) 138 } 139 for k, v := range methodConfig.QueryParamsMap { 140 if maxKey < k { 141 maxKey = k 142 } 143 params := req.QueryParameters(v) 144 if len(params) == 1 { 145 argsMap[k] = params[0] 146 } else { 147 argsMap[k] = params 148 } 149 } 150 for k, v := range methodConfig.HeadersMap { 151 if maxKey < k { 152 maxKey = k 153 } 154 argsMap[k] = req.HeaderParameter(v) 155 } 156 if methodConfig.Body >= 0 { 157 if maxKey < methodConfig.Body { 158 maxKey = methodConfig.Body 159 } 160 m := make(map[string]interface{}) 161 // TODO read as a slice 162 if err := req.ReadEntity(&m); err != nil { 163 return nil, perrors.Errorf("[Go restful] Read body entity as map[string]interface{} error:%v", err) 164 } 165 argsMap[methodConfig.Body] = m 166 } 167 args := make([]interface{}, maxKey+1) 168 for k, v := range argsMap { 169 if k >= 0 { 170 args[k] = v 171 } 172 } 173 return args, nil 174 } 175 176 // getArgsFromRequest get arguments from server.RestServerRequest 177 func getArgsFromRequest(req RestServerRequest, argsTypes []reflect.Type, methodConfig *rest_config.RestMethodConfig) ([]interface{}, error) { 178 argsLength := len(argsTypes) 179 args := make([]interface{}, argsLength) 180 for i, t := range argsTypes { 181 args[i] = reflect.Zero(t).Interface() 182 } 183 if err := assembleArgsFromPathParams(methodConfig, argsLength, argsTypes, req, args); err != nil { 184 return nil, err 185 } 186 if err := assembleArgsFromQueryParams(methodConfig, argsLength, argsTypes, req, args); err != nil { 187 return nil, err 188 } 189 if err := assembleArgsFromBody(methodConfig, argsTypes, req, args); err != nil { 190 return nil, err 191 } 192 if err := assembleArgsFromHeaders(methodConfig, req, argsLength, argsTypes, args); err != nil { 193 return nil, err 194 } 195 return args, nil 196 } 197 198 // assembleArgsFromHeaders assemble arguments from headers 199 func assembleArgsFromHeaders(methodConfig *rest_config.RestMethodConfig, req RestServerRequest, argsLength int, argsTypes []reflect.Type, args []interface{}) error { 200 for k, v := range methodConfig.HeadersMap { 201 param := req.HeaderParameter(v) 202 if k < 0 || k >= argsLength { 203 return perrors.Errorf("[Go restful] Header param parse error, the index %v args of method:%v doesn't exist", k, methodConfig.MethodName) 204 } 205 t := argsTypes[k] 206 if t.Kind() == reflect.Ptr { 207 t = t.Elem() 208 } 209 if t.Kind() == reflect.String { 210 args[k] = param 211 } else { 212 return perrors.Errorf("[Go restful] Header param parse error, the index %v args's type isn't string", k) 213 } 214 } 215 return nil 216 } 217 218 // assembleArgsFromBody assemble arguments from body 219 func assembleArgsFromBody(methodConfig *rest_config.RestMethodConfig, argsTypes []reflect.Type, req RestServerRequest, args []interface{}) error { 220 if methodConfig.Body >= 0 && methodConfig.Body < len(argsTypes) { 221 t := argsTypes[methodConfig.Body] 222 kind := t.Kind() 223 if kind == reflect.Ptr { 224 t = t.Elem() 225 } 226 var ni interface{} 227 if t.String() == "[]interface {}" { 228 ni = make([]map[string]interface{}, 0) 229 } else if t.String() == "interface {}" { 230 ni = make(map[string]interface{}) 231 } else { 232 n := reflect.New(t) 233 if n.CanInterface() { 234 ni = n.Interface() 235 } 236 } 237 if err := req.ReadEntity(&ni); err != nil { 238 return perrors.Errorf("[Go restful] Read body entity error, error is %v", perrors.WithStack(err)) 239 } 240 args[methodConfig.Body] = ni 241 } 242 return nil 243 } 244 245 // assembleArgsFromQueryParams assemble arguments from query params 246 func assembleArgsFromQueryParams(methodConfig *rest_config.RestMethodConfig, argsLength int, argsTypes []reflect.Type, req RestServerRequest, args []interface{}) error { 247 var ( 248 err error 249 param interface{} 250 i64 int64 251 ) 252 for k, v := range methodConfig.QueryParamsMap { 253 if k < 0 || k >= argsLength { 254 return perrors.Errorf("[Go restful] Query param parse error, the index %v args of method:%v doesn't exist", k, methodConfig.MethodName) 255 } 256 t := argsTypes[k] 257 kind := t.Kind() 258 if kind == reflect.Ptr { 259 t = t.Elem() 260 kind = t.Kind() 261 } 262 if kind == reflect.Slice { 263 param = req.QueryParameters(v) 264 } else if kind == reflect.String { 265 param = req.QueryParameter(v) 266 } else if kind == reflect.Int { 267 param, err = strconv.Atoi(req.QueryParameter(v)) 268 } else if kind == reflect.Int32 { 269 i64, err = strconv.ParseInt(req.QueryParameter(v), 10, 32) 270 if err == nil { 271 param = int32(i64) 272 } 273 } else if kind == reflect.Int64 { 274 param, err = strconv.ParseInt(req.QueryParameter(v), 10, 64) 275 } else { 276 return perrors.Errorf("[Go restful] Query param parse error, the index %v args's type isn't int or string or slice", k) 277 } 278 if err != nil { 279 return perrors.Errorf("[Go restful] Query param parse error, error:%v", perrors.WithStack(err)) 280 } 281 args[k] = param 282 } 283 return nil 284 } 285 286 // assembleArgsFromPathParams assemble arguments from path params 287 func assembleArgsFromPathParams(methodConfig *rest_config.RestMethodConfig, argsLength int, argsTypes []reflect.Type, req RestServerRequest, args []interface{}) error { 288 var ( 289 err error 290 param interface{} 291 i64 int64 292 ) 293 for k, v := range methodConfig.PathParamsMap { 294 if k < 0 || k >= argsLength { 295 return perrors.Errorf("[Go restful] Path param parse error, the index %v args of method:%v doesn't exist", k, methodConfig.MethodName) 296 } 297 t := argsTypes[k] 298 kind := t.Kind() 299 if kind == reflect.Ptr { 300 t = t.Elem() 301 kind = t.Kind() 302 } 303 if kind == reflect.Int { 304 param, err = strconv.Atoi(req.PathParameter(v)) 305 } else if kind == reflect.Int32 { 306 i64, err = strconv.ParseInt(req.PathParameter(v), 10, 32) 307 if err == nil { 308 param = int32(i64) 309 } 310 } else if kind == reflect.Int64 { 311 param, err = strconv.ParseInt(req.PathParameter(v), 10, 64) 312 } else if kind == reflect.String { 313 param = req.PathParameter(v) 314 } else { 315 return perrors.Errorf("[Go restful] Path param parse error, the index %v args's type isn't int or string", k) 316 } 317 if err != nil { 318 return perrors.Errorf("[Go restful] Path param parse error, error is %v", perrors.WithStack(err)) 319 } 320 args[k] = param 321 } 322 return nil 323 }