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 a http.ResponseWriter
(with a regular webserver) for cross domain requests, as this doesn't take a http.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 get 405 (Method Not Allowed)
(not sure if this is because I can't make x-domain requests though?)
Any insight greatly appreciated.
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!