使用golang实现通过web页面访问http+jsonrpc。

huangapple go评论91阅读模式
英文:

golang http+jsonrpc access from web page

问题

我之前使用过Go语言的net/rpcnet/rpc/jsonrpc包来在Go进程之间进行连接,但我想知道是否有一种方法可以仅使用标准库中的服务器工具来连接到HTTP JSONRPC服务器(并不是说我不能自己编写,只是不想做的话就不用做)。

这是我基本的服务器设置:

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)

我希望能够从网页或简单的命令行CURL调用中访问它 - 只是一个普通的POST请求。

然而,这行代码:http://golang.org/src/net/rpc/server.go?s=20445:20475#L670 似乎表明它期望一个HTTP客户端发起CONNECT请求,然后直接将JSON RPC请求写入流中,并以相同的方式接收回复。我不知道这是否在浏览器中可行,但它肯定不像简单的POST请求那样常见或兼容。

是否有一种方法可以启动一个JSON RPC服务器,我可以通过传统的XMLHttpRequest进行POST请求?

编辑:糟糕 - 上面的代码甚至没有使用jsonrpc的东西 - 这可能是在尝试使用Gob,但无论如何 - 问题是一样的 - src/net/rpc/server.go中的代码不会处理POST请求,所以无论如何这条路都行不通,无论服务器编解码器如何。

英文:

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.

答案1

得分: 8

FWIW,我通过创建一个简单的HTTP处理程序,将HTTP请求/响应适配到ServerCodec,使其正常工作。看起来效果很好。

以下是作为测试的工作代码:

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/rpc"
	"net/rpc/jsonrpc"
	"testing"
)

// 将HTTP连接适配为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 }

// 我们的服务
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\n")

	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\n", string(b))

}

希望对你有帮助!

英文:

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\n")
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\n", string(b))
}

答案2

得分: -1

一个RPC框架应该有语言支持列表,我没有使用json-rpc,但它应该通过这个链接支持JavaScript语言。你需要添加其中列出的JavaScript客户端SDK之一。

英文:

a RPC framework shoud have language supports list, I not used json-rpc, but it should support javascript language by this link. you need add one of the javascript client sdk listed there.

huangapple
  • 本文由 发表于 2015年7月14日 11:03:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/31396924.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定