golang http+jsonrpc 网页访问
golang http+jsonrpc access from web page
我已经使用了 Go 的 net/rpc
和 net/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 服务器,我可以 POST 使用好的 XMLHttpRequest?
编辑:废话 - 上面甚至没有使用 jsonrpc 东西 - 这可能是在尝试使用 Gob,但无论如何 - 问题是一样的 - src/net/rpc/server.go 中的代码不会处理 POSTs,因此无论服务器编解码器如何,这条路由总体上都无法正常工作。
RPC 框架应该有语言支持列表,我没有使用 json-rpc,但它应该支持 javascript 语言this link。您需要添加此处列出的 javascript 客户端 sdk 之一。
FWIW,我通过制作一个简单的 HTTP 处理程序使 HTTP request/response 适应 ServerCodec 来实现这一点。似乎很有魅力。
下面是作为测试的工作代码:
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))
}
我已经使用了 Go 的 net/rpc
和 net/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 服务器,我可以 POST 使用好的 XMLHttpRequest?
编辑:废话 - 上面甚至没有使用 jsonrpc 东西 - 这可能是在尝试使用 Gob,但无论如何 - 问题是一样的 - src/net/rpc/server.go 中的代码不会处理 POSTs,因此无论服务器编解码器如何,这条路由总体上都无法正常工作。
RPC 框架应该有语言支持列表,我没有使用 json-rpc,但它应该支持 javascript 语言this link。您需要添加此处列出的 javascript 客户端 sdk 之一。
FWIW,我通过制作一个简单的 HTTP 处理程序使 HTTP request/response 适应 ServerCodec 来实现这一点。似乎很有魅力。
下面是作为测试的工作代码:
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))
}