初步简化safe_guard
This commit is contained in:
parent
4cb117232d
commit
9845a661f6
17
cmd/rpc_saft_guard/main.go
Normal file
17
cmd/rpc_saft_guard/main.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"rpc_safe_guard_01/pkg/handler"
|
||||
"rpc_safe_guard_01/pkg/otto"
|
||||
)
|
||||
|
||||
func main() {
|
||||
otto.InitOtto()
|
||||
|
||||
http.HandleFunc("/", handler.Handler)
|
||||
err := http.ListenAndServe("localhost:8081", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
16
go.mod
Normal file
16
go.mod
Normal file
@ -0,0 +1,16 @@
|
||||
module rpc_safe_guard_01
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/robertkrimen/otto v0.2.1
|
||||
github.com/stretchr/testify v1.8.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
23
go.sum
Normal file
23
go.sum
Normal file
@ -0,0 +1,23 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/robertkrimen/otto v0.2.1 h1:FVP0PJ0AHIjC+N4pKCG9yCDz6LHNPCwi/GKID5pGGF0=
|
||||
github.com/robertkrimen/otto v0.2.1/go.mod h1:UPwtJ1Xu7JrLcZjNWN8orJaM5n5YEtqL//farB5FlRY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
|
||||
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
19
pkg/handler/excutor.go
Normal file
19
pkg/handler/excutor.go
Normal file
@ -0,0 +1,19 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"rpc_safe_guard_01/pkg/interpreter"
|
||||
"rpc_safe_guard_01/pkg/okapi"
|
||||
)
|
||||
|
||||
func Execute(req okapi.Request) (string, error) {
|
||||
vm := interpreter.GetInstance()
|
||||
value, err := vm.Run(req.Body.Params["code"])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
data, err := value.ToString()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return data, nil
|
||||
}
|
36
pkg/handler/handler.go
Normal file
36
pkg/handler/handler.go
Normal file
@ -0,0 +1,36 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"rpc_safe_guard_01/pkg/okapi"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Handler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
contentType := r.Header.Get("Content-Type")
|
||||
if !strings.Contains(contentType, "application/json") {
|
||||
http.Error(w, "Unsupported media type", http.StatusUnsupportedMediaType)
|
||||
return
|
||||
}
|
||||
|
||||
var req okapi.Request
|
||||
err := req.Decode(r)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
data, err := Execute(req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Write([]byte(data))
|
||||
}
|
16
pkg/interpreter/otto.go
Normal file
16
pkg/interpreter/otto.go
Normal file
@ -0,0 +1,16 @@
|
||||
package interpreter
|
||||
|
||||
import (
|
||||
"github.com/robertkrimen/otto"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var instance *otto.Otto
|
||||
var once sync.Once
|
||||
|
||||
func GetInstance() *otto.Otto {
|
||||
once.Do(func() {
|
||||
instance = otto.New()
|
||||
})
|
||||
return instance
|
||||
}
|
47
pkg/okapi/okapi.go
Normal file
47
pkg/okapi/okapi.go
Normal file
@ -0,0 +1,47 @@
|
||||
package okapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
AppKey string
|
||||
ApiName string
|
||||
ApiVersion string
|
||||
Body RequestBody
|
||||
}
|
||||
|
||||
type RequestBody struct {
|
||||
OaSessionID string `json:"oa-session-id,omitempty"`
|
||||
OaAppMarketID string `json:"oa-app-market-id,omitempty"`
|
||||
OaAppVersion string `json:"oa-app-version,omitempty"`
|
||||
OaDeviceID string `json:"oa-device-id,omitempty"`
|
||||
OaSign string `json:"oa-sign,omitempty"`
|
||||
Timestamp string `json:"timestamp,omitempty"`
|
||||
Params map[string]interface{} `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
func (req *Request) Decode(r *http.Request) error {
|
||||
reqBody, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Restore the io.ReadCloser to its original state
|
||||
r.Body = io.NopCloser(bytes.NewBuffer(reqBody))
|
||||
if err = r.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.AppKey = r.Form.Get("appkey")
|
||||
req.ApiName = r.Form.Get("api")
|
||||
req.ApiVersion = r.Form.Get("version")
|
||||
err = json.Unmarshal(reqBody, &req.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
47
pkg/okrpc/okrpc.go
Normal file
47
pkg/okrpc/okrpc.go
Normal file
@ -0,0 +1,47 @@
|
||||
package okrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
RpcRequestUrl = "http://127.0.0.1:8080"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
Class string `json:"class"`
|
||||
Method string `json:"method"`
|
||||
Args []interface{} `json:"args"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorCode string `json:"errorCode,omitempty"`
|
||||
ErrorMessage string `json:"errorMessage,omitempty"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func (r Request) SendRpcRequest() (string, error) {
|
||||
data, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
request, err := http.NewRequest("POST", RpcRequestUrl, bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
request.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(request)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(body), nil
|
||||
}
|
40
pkg/okrpc/okrpc_test.go
Normal file
40
pkg/okrpc/okrpc_test.go
Normal file
@ -0,0 +1,40 @@
|
||||
package okrpc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSendRpcRequest(t *testing.T) {
|
||||
request := Request{
|
||||
Class: "rpcLinker.SbxQitListService",
|
||||
Method: "executeChain",
|
||||
}
|
||||
|
||||
request.Args = append(request.Args, "1")
|
||||
arg0 := make(map[string]interface{})
|
||||
arg0["pagination"] = make(map[string]interface{})
|
||||
arg0["pagination"].(map[string]interface{})["current"] = 1
|
||||
arg0["pagination"].(map[string]interface{})["pageSize"] = 10
|
||||
arg0["pagination"].(map[string]interface{})["returnAll"] = false
|
||||
request.Args = append(request.Args, arg0)
|
||||
|
||||
resp, err := request.SendRpcRequest()
|
||||
assert.Nil(t, err)
|
||||
t.Log(resp)
|
||||
}
|
||||
|
||||
func TestUnmarshal(t *testing.T) {
|
||||
str := `[{'pagination':{'returnAll':false,'current':1,'pageSize':10}},1]`
|
||||
|
||||
var data []interface{}
|
||||
err := json.Unmarshal([]byte(str), &data)
|
||||
if err != nil {
|
||||
fmt.Println("JSON unmarshaling failed:", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("%#v\n", data)
|
||||
}
|
73
pkg/otto/otto.go
Normal file
73
pkg/otto/otto.go
Normal file
@ -0,0 +1,73 @@
|
||||
package otto
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/robertkrimen/otto"
|
||||
"rpc_safe_guard_01/pkg/interpreter"
|
||||
"rpc_safe_guard_01/pkg/okrpc"
|
||||
)
|
||||
|
||||
const (
|
||||
RpcServiceName = "rpcRequest"
|
||||
RpcName = "gw"
|
||||
ExitName = "exit"
|
||||
)
|
||||
|
||||
var ErrorCodeMap = map[int]string{
|
||||
10001: "rpc request error",
|
||||
}
|
||||
|
||||
func InitOtto() {
|
||||
// 注册通用方法到otto里
|
||||
instance := interpreter.GetInstance()
|
||||
err := instance.Set(RpcName, map[string]interface{}{
|
||||
RpcServiceName: call,
|
||||
ExitName: exit,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func call(call otto.FunctionCall) otto.Value {
|
||||
if len(call.ArgumentList) != 2 {
|
||||
value, _ := otto.ToValue(errors.New("argument invalid"))
|
||||
return value
|
||||
}
|
||||
rpcName := call.Argument(0)
|
||||
param := call.Argument(1)
|
||||
p, err := param.ToString()
|
||||
if err != nil {
|
||||
value, _ := otto.ToValue(err)
|
||||
return value
|
||||
}
|
||||
var args []interface{}
|
||||
err = json.Unmarshal([]byte(p), &args)
|
||||
if err != nil {
|
||||
value, _ := otto.ToValue(err)
|
||||
return value
|
||||
}
|
||||
var req okrpc.Request
|
||||
req.Class = rpcName.String()
|
||||
req.Method = "executeChain"
|
||||
req.Args = args
|
||||
resp, err := req.SendRpcRequest()
|
||||
if err != nil {
|
||||
value, _ := otto.ToValue(err)
|
||||
return value
|
||||
}
|
||||
value, _ := otto.ToValue(resp)
|
||||
return value
|
||||
}
|
||||
|
||||
func exit(call otto.FunctionCall) otto.Value {
|
||||
code, err := call.Argument(0).ToInteger()
|
||||
if err != nil {
|
||||
value, _ := otto.ToValue(errors.New("the code is not number"))
|
||||
return value
|
||||
}
|
||||
// 此处传入Api Error Code,先用map代替
|
||||
value, _ := otto.ToValue(ErrorCodeMap[int(code)])
|
||||
return value
|
||||
}
|
44
question.md
Normal file
44
question.md
Normal file
@ -0,0 +1,44 @@
|
||||
## 1. 简化思路
|
||||
|
||||
例如:
|
||||
```javascript
|
||||
// 1. 检查用户名是否已经注册
|
||||
hasUser = rpc.call("com.swallow.user.checkUserName", user.name)
|
||||
|
||||
if (hasUser != null) {
|
||||
rpc.error("code", "message")
|
||||
}
|
||||
// 2. 检查手机号是否已经注册
|
||||
hasPhone = rpc.call("com.swallow.user.checkPhoneNumber", user.phoneNumber)
|
||||
|
||||
if (hasPhone != null) {
|
||||
rpc.error("code", "message")
|
||||
}
|
||||
|
||||
// 3. 创建用户
|
||||
create = rpc.call("com.swallow.user.create", user)
|
||||
|
||||
if (create) {
|
||||
rpc.success({ "data": create })
|
||||
}
|
||||
```
|
||||
目前的简化思路就是我在后台只注册rpc参数,并给rpc注册call/error等方法,配置文件全部弃掉
|
||||
|
||||
## 2、call函数使用
|
||||
|
||||
- 第一个参数是要调用的rpc名字,可以来自于rpc linker也可以来自于java service
|
||||
- 第二个参数是写成类似于这样的来接受0个或多个参数的请求体,请求体将会传递给rpc方法的请求参数
|
||||
```javascript
|
||||
arg = {
|
||||
"name": "test",
|
||||
"age": 12,
|
||||
"other": "ssss"
|
||||
}
|
||||
rpc.call("com.swallow.user.create", arg)
|
||||
```
|
||||
|
||||
## 3、条件限定
|
||||
- go后台拿到rpc响应后是不是还需要根据条件限定,对响应进行校验
|
||||
- 例如HTML或者APP传递条件给我(username != null),我需要根据这个条件加个判断再返回响应给js。
|
||||
|
||||
## 4、前台传递的条件是单个还是多个?
|
14
test/rpcLinker.SbxQitListService.http
Normal file
14
test/rpcLinker.SbxQitListService.http
Normal file
@ -0,0 +1,14 @@
|
||||
POST http://localhost:8081/okapi3?api=rpcLinker.SbxOrderSearchService&version=1.0&appkey=c94ec1fc-58c1-41c6-9980-ead078ae2c97
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"oa-session-id": "7E2532FF3A72D64A91B9810EBBDF2441",
|
||||
"oa-app-market-id": "678",
|
||||
"oa-app-version": "1.0",
|
||||
"oa-device-id": "1911151415",
|
||||
"oa-sign": "1a6f78424a4874bdfb3ee716c372e547",
|
||||
"timestamp": "1686919817370370",
|
||||
"params": {
|
||||
"code": "gw.rpcRequest('rpcLinker.SbxQitListService', '[{\"pagination\":{\"returnAll\":false,\"current\":1,\"pageSize\":10}},1]')"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user