英文:
JSON RPC request in Golang with Gorilla/rpc
问题
我正在尝试使用Gorilla/rpc
包来建立一个RPC,以接收请求并回复响应(显然)。
首先,我正在尝试使用Gorilla/rpc
提供的示例。
这是我的代码:
type HelloArgs struct {
Who string
}
type HelloReply struct {
Message string
}
type HelloService struct{}
func (h *HelloService) Say(r *http.Request, args *HelloArgs, reply *HelloReply) error {
reply.Message = "Hello, " + args.Who + "!"
return nil
}
func main() {
r := mux.NewRouter()
jsonRPC := rpc.NewServer()
jsonCodec := json.NewCodec()
jsonRPC.RegisterCodec(jsonCodec, "application/json")
jsonRPC.RegisterCodec(jsonCodec, "application/json; charset=UTF-8") // For firefox 11 and other browsers which append the charset=UTF-8
jsonRPC.RegisterService(new(HelloService), "")
r.Handle("/api", jsonRPC)
http.ListenAndServe(":"+port, nil)
}
我有几个问题:
-
我不确定如何设置
Access-Control-Allow-Origin
头,就像我通常在http.ResponseWriter
上(使用常规的Web服务器)为跨域请求设置一样,因为它不接受http.ResponseWriter
作为参数。 -
我应该发送什么来访问
HelloService.Say
方法?我尝试过{ method: "HelloService.Say", params:[{Who: "Me"}]}
,但是我得到了405 (Method Not Allowed)
(不确定是否因为我不能进行跨域请求?)
非常感谢任何见解。
英文:
I'm trying to use the Gorilla/rpc
package to set up a RPC to receive a request and reply with a response (obviously).
First I'm trying with the example provided with Gorilla/rpc
Here's my code:
type HelloArgs struct {
Who string
}
type HelloReply struct {
Message string
}
type HelloService struct{}
func (h *HelloService) Say(r *http.Request, args *HelloArgs, reply *HelloReply) error {
reply.Message = "Hello, " + args.Who + "!"
return nil
}
func main() {
r := mux.NewRouter()
jsonRPC := rpc.NewServer()
jsonCodec := json.NewCodec()
jsonRPC.RegisterCodec(jsonCodec, "application/json")
jsonRPC.RegisterCodec(jsonCodec, "application/json; charset=UTF-8") // For firefox 11 and other browsers which append the charset=UTF-8
jsonRPC.RegisterService(new(HelloService), "")
r.Handle("/api", jsonRPC)
http.ListenAndServe(":"+port, nil)
}
I have a couple of issues:
-
I'm not sure how I would set a
Access-Control-Allow-Origin
header like I normally would on ahttp.ResponseWriter
(with a regular webserver) for cross domain requests, as this doesn't take ahttp.ResponseWriter
as an argument. -
What would I actually send to access the
HelloService.Say
method? I've tried{ method: "HelloService.Say", params:[{Who: "Me"}]}
but I get405 (Method Not Allowed)
(not sure if this is because I can't make x-domain requests though?)
Any insight greatly appreciated.
答案1
得分: 2
Gorilla/rpc/json
的CodecRequest.WriteResponse
(实现了Gorilla/rpc
的CodecRequest
)是代码中唯一涉及http.ResponseWriter
的地方。
这意味着我们必须有自己的CodecRequest
实现来设置CORS头。
服务器使用的每个CodecRequest
实际上都是由Codec
生成的;可以说,Codec
是生成CodecRequest
的工厂。
这意味着我们必须创建一个Codec
来生成设置CORS头的CodecRequest
。
Go的一个很棒的特点是,组合这种额外行为非常容易!
试试这个:
package cors_codec
import (
"Gorilla/rpc"
"net/http"
"strings"
)
//interface: ain't nobody dope like me I feel so fresh and clean
func CodecWithCors([]string corsDomains, unpimped rpc.Codec) rpc.Codec {
return corsCodecRequest{corsDomains, unpimped}
}
type corsCodecRequest struct {
corsDomains []string
underlyingCodecRequest rpc.CodecRequest
}
//override exactly one method of the underlying anonymous field and delegate to it.
func (ccr corsCodecRequest) WriteResponse(w http.ResponseWriter, reply interface{}, methodErr error) error {
w.Header().add("Access-Control-Allow-Origin", strings.join(ccr.corsDomains, " "))
return ccr.underlyingCodecRequest.WriteResponse(w, reply, error)
}
type corsCodec struct {
corsDomains []string
underlyingCodec rpc.Codec
}
//override exactly one method of the underlying anonymous field and delegate to it.
func (cc corsCodec) NewRequest(req *http.Request) rpc.CodecRequest {
return corsCodecRequest{cc.corsDomains, cc.underlyingCodec.NewRequest(req)}
}
这是一个有趣的练习!
英文:
EDITED: to fix bad use of 'type synonyms'
For number 1:
Gorilla/rpc/json
's CodecRequest.WriteResponse
(which implements Gorilla/rpc
's CodecRequest
) is the one place where the code touches an http.ResponseWriter
.
This means that we have to have our own implementation of CodecRequest
which sets the CORS header.
Every CodecRequest
used by the server is actually generated by a Codec
; Codec
s are factories for making CodecRequests
, to put it another way.
This means that we have to create a Codec
to generate our CodecRequest
s that will set CORS headers.
The great thing about Go is that it's really easy to compose this extra behavior!
Try this:
package cors_codec
import (
"Gorilla/rpc"
"net/http"
"strings"
)
//interface: ain't nobody dope like me I feel so fresh and clean
func CodecWithCors([]string corsDomains, unpimped rpc.Codec) rpc.Codec {
return corsCodecRequest{corsDomains, unpimped}
}
type corsCodecRequest struct {
corsDomains []string
underlyingCodecRequest rpc.CodecRequest
}
//override exactly one method of the underlying anonymous field and delegate to it.
func (ccr corsCodecRequest) WriteResponse(w http.ResponseWriter, reply interface{}, methodErr error) error {
w.Header().add("Access-Control-Allow-Origin", strings.join(ccr.corsDomains, " "))
return ccr.underlyingCodecRequest.WriteResponse(w, reply, error)
}
type corsCodec struct {
corsDomains []string
underlyingCodec rpc.Codec
}
//override exactly one method of the underlying anonymous field and delegate to it.
func (cc corsCodec) NewRequest(req *http.Request) rpc.CodecRequest {
return corsCodecRequest{cc.corsDomains, cc.underlyingCodec.NewRequest(req)}
}
That was a fun exercise!
答案2
得分: 0
我知道这是一个相当旧的问题,但实际上有一种更简单的方法来实现这个。
你可以通过rs/cors
和justinas/alice
包在几行代码中实现这个。
func main() {
chain := alice.New(cors.Default().Handler)
server := rpc.NewServer()
server.RegisterCodec(json2.NewCodec(), "application/json")
server.RegisterService(new(HelloService), "")
http.Handle("/rpc", chain.Then(server))
http.ListenAndServe(":8081", nil)
}
英文:
I know this is a pretty old question but there is actually an easier way to achieve this.
You can do this thanks to rs/cors
and justinas/alice
packages in few lines.
func main() {
chain := alice.New(cors.Default().Handler)
server := rpc.NewServer()
server.RegisterCodec(json2.NewCodec(), "application/json")
server.RegisterService(new(HelloService), "")
http.Handle("/rpc", chain.Then(server))
http.ListenAndServe(":8081", nil)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论