du7979 2015-07-14 03:03
浏览 131
已采纳

从网页访问golang http + jsonrpc

I've used Go's net/rpc and net/rpc/jsonrpc packages a bit to perform connections between Go processes, however I'm wondering if there is a way to connect to an HTTP JSONRPC server using only the server tooling from the standard library (not that I have a problem writing my own, just don't want to do it if I don't have to).

This is the basic server setup I have:

arith := new(server.Arith)

server := rpc.NewServer()
server.Register(arith)

server.HandleHTTP(rpc.DefaultRPCPath, rpc.DefaultDebugPath)

listener, e := net.Listen("tcp", ":4321")
if e != nil {
    log.Fatal("listen error:", e)
}
defer listener.Close()

http.Serve(listener, http.DefaultServeMux)

And I'd like to be able to be hitting this from a web page or a simple command line CURL call - just a regular POST.

However, this line: http://golang.org/src/net/rpc/server.go?s=20445:20475#L670 appears to indicate that it expects an HTTP client to issue a CONNECT and then directly write the JSON RPC request to the stream and receive the reply back the same way. I don't know if this is even possible from a browser, but it certainly is not as common or compatible as a simple POST.

Is there a way to start a JSON RPC server that I can just POST to using good ol' XMLHttpRequest ?

EDIT: Crap - the above is not even using the jsonrpc stuff - this is probably trying to use Gob, but whatever - the problem is the same - the code in src/net/rpc/server.go is not going to handle POSTs, so this route overall isn't going to work regardless of server codec.

  • 写回答

2条回答 默认 最新

  • duanqinjiao5244 2015-07-16 02:13
    关注

    FWIW, I got this working by making a simple HTTP handler that adapts the HTTP request/response to a ServerCodec. Seems to work like a charm.

    Here's the working code as a test:

    import (
        "bytes"
        "fmt"
        "io"
        "io/ioutil"
        "log"
        "net"
        "net/http"
        "net/rpc"
        "net/rpc/jsonrpc"
        "testing"
    )
    
    // adapt HTTP connection to ReadWriteCloser
    type HttpConn struct {
        in  io.Reader
        out io.Writer
    }
    
    func (c *HttpConn) Read(p []byte) (n int, err error)  { return c.in.Read(p) }
    func (c *HttpConn) Write(d []byte) (n int, err error) { return c.out.Write(d) }
    func (c *HttpConn) Close() error                      { return nil }
    
    // our service
    type CakeBaker struct{}
    
    func (cb *CakeBaker) BakeIt(n int, msg *string) error {
        *msg = fmt.Sprintf("your cake has been bacon (%d)", n)
        return nil
    }
    
    func TestHTTPServer(t *testing.T) {
    
        fmt.Printf("TestHTTPServer
    ")
    
        cb := &CakeBaker{}
    
        server := rpc.NewServer()
        server.Register(cb)
    
        listener, e := net.Listen("tcp", ":4321")
        if e != nil {
            log.Fatal("listen error:", e)
        }
        defer listener.Close()
    
        go http.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    
            if r.URL.Path == "/bake-me-a-cake" {
                serverCodec := jsonrpc.NewServerCodec(&HttpConn{in: r.Body, out: w})
                w.Header().Set("Content-type", "application/json")
                w.WriteHeader(200)
                err := server.ServeRequest(serverCodec)
                if err != nil {
                    log.Printf("Error while serving JSON request: %v", err)
                    http.Error(w, "Error while serving JSON request, details have been logged.", 500)
                    return
                }
            }
    
        }))
    
        resp, err := http.Post("http://localhost:4321/bake-me-a-cake", "application/json", bytes.NewBufferString(
            `{"jsonrpc":"2.0","id":1,"method":"CakeBaker.BakeIt","params":[10]}`,
        ))
        if err != nil {
            panic(err)
        }
        defer resp.Body.Close()
        b, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            panic(err)
        }
    
        fmt.Printf("returned JSON: %s
    ", string(b))
    
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 虚拟机打包apk出现错误
  • ¥30 最小化遗憾贪心算法上界
  • ¥15 用visual studi code完成html页面
  • ¥15 聚类分析或者python进行数据分析
  • ¥15 逻辑谓词和消解原理的运用
  • ¥15 三菱伺服电机按启动按钮有使能但不动作
  • ¥15 js,页面2返回页面1时定位进入的设备
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝