官术网_书友最值得收藏!

JSON-RPC over HTTP

In this last example, we will look at the net/rpc/jsonrpc package that provides a built-in codec for serializing and deserializing to the JSON-RPC standard. We will also look at how we can send these responses over HTTP, whilst you may ask why not just use REST, and to some extent I will agree with you, it is an interesting example to be able to see how we can extend the standard framework.

The StartServer method contains nothing we have not seen before it is the standard rpc server setup, the main difference is line 42 where instead of starting the RPC server we are starting an http server and passing the listener to it along with a handler:

rpc_http_json/server/server.go

33 func StartServer() { 
34 helloWorld := new(HelloWorldHandler)
35 rpc.Register(helloWorld)
36
37 l, err := net.Listen("tcp", fmt.Sprintf(":%v", port))
38 if err != nil {
39 log.Fatal(fmt.Sprintf("Unable to listen on given port: %s", err))
40 }
41
42 http.Serve(l, http.HandlerFunc(httpHandler))
43 }

The handler we are passing to the server is where the magic happens:

45 func httpHandler(w http.ResponseWriter, r *http.Request) { 
46 serverCodec := jsonrpc.NewServerCodec(&HttpConn{in: r.Body, out: w})
47 err := rpc.ServeRequest(serverCodec)
48 if err != nil {
49 log.Printf("Error while serving JSON request: %v", err)
50 http.Error(w, "Error while serving JSON request, details have been logged.", 500)
51 return
52 }
53 }

In line 46, we are calling the jsonrpc.NewServerCodec function and passing to it a type that implements io.ReadWriteCloser. The NewServerCodec method returns a type that implements rpc.ClientCodec, which has the following methods:

type ClientCodec interface { 
// WriteRequest must be safe for concurrent use by multiple goroutines.
WriteRequest(*Request, interface{}) error
ReadResponseHeader(*Response) error
ReadResponseBody(interface{}) error

Close() error
}

A ClientCodec type implements the writing of RPC request and reading RPC responses. To write a request to the connection a client calls the WriteRequest method. To read the response, the client must call ReadResponseHeader and ReadResponseBody as a pair. Once the body has been read, it is the client's responsibility to call the Close method to close the connection. If a nil interface is passed to ReadResponseBody then the body of the response should be read and then discarded:

17 type HttpConn struct { 
18 in io.Reader
19 out io.Writer
20 }
21
22 func (c *HttpConn) Read(p []byte) (n int, err error) { return c.in.Read(p) }
23 func (c *HttpConn) Write(d []byte) (n int, err error) { return c.out.Write(d) }
24 func (c *HttpConn) Close() error { return nil }

The NewServerCodec method requires that we pass it a type that implements the ReadWriteCloser interface. As we do not have such a type passed to us as parameters in the httpHandler method we have defined our own type, HttpConn, which encapsulates the http.Request body, which implements io.Reader, and the ResponseWriter method, that implements io.Writer. We can then write our own methods that proxy the calls to the reader and writer creating a type that has the correct interface.

And that is it for our short intro to RPC with the standard libraries; we will see when we look at some frameworks more in depth in Chapter 3, Introducing Docker, how these can be used to build a production microservice.

主站蜘蛛池模板: 富民县| 芦山县| 新宾| 辽宁省| 花莲市| 长阳| 鹤峰县| 新蔡县| 宁阳县| 巴林右旗| 阿勒泰市| 冷水江市| 光泽县| 东乌珠穆沁旗| 阿瓦提县| 许昌县| 巴马| 乌兰浩特市| 措美县| 江阴市| 成都市| 西城区| 富锦市| 平原县| 巫山县| 商城县| 万山特区| 乌拉特前旗| 郸城县| 宜丰县| 和硕县| 大同市| 通海县| 象州县| 临高县| 唐河县| 乌海市| 吉林市| 山西省| 色达县| 会昌县|