سؤال

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:

  1. 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.

  2. 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.

هل كانت مفيدة؟

المحلول

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; Codecs are factories for making CodecRequests, to put it another way.

This means that we have to create a Codec to generate our CodecRequests 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!

نصائح أخرى

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)
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top