Go websocket jsonrpc 浏览器连接关闭

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

Go websocket jsonrpc browser connection close

问题

我有一个WebSocket JSON-RPC服务器示例,我想要在浏览器中使用。当访问URL "http:localhost:8080"时,浏览器可以正确地打开WebSocket连接。但是当浏览器发送WebSocket请求时,服务器会关闭WebSocket连接。我甚至看不到服务器上调用RPC方法的痕迹。

然而,从Go客户端调用服务器却完全正常。

server.go

package main

import (
    "log"
    "net/http"
    "net/rpc"
    "net/rpc/jsonrpc"
    "github.com/gorilla/websocket"
)

type Service struct{}

func (t *Service) Echo(req *string, res *string) error {
    log.Printf("Service.Echo")
    *res = *req
    log.Printf("Service.Echo req:%s res:%s", *req, *res)
    return nil
}

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
}

func serveWS(w http.ResponseWriter, r *http.Request) {
    ws, err := upgrader.Upgrade(w, r, nil)
    defer ws.Close()

    if err != nil {
        log.Println(err)
        return
    }
    jsonrpc.ServeConn(ws.UnderlyingConn())
}

func main() {
    rpc.Register(new(Service))
    http.Handle("/", http.FileServer(http.Dir("web")))
    http.HandleFunc("/ws", serveWS)
    http.ListenAndServe(":8080", nil)
}

web/index.html

<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript">
    var ws = new WebSocket("ws://localhost:8080/ws");
    ws.onopen = function(ev){
        alert("open");
    }
    ws.onmessage = function(ev){
        alert("message");
    }
    ws.onclose = function(ev){
        alert("close");
    }

    function send() {
        msg = {
            method: "Service.Echo",
            params: "hello",
            id: 0
        };
        var s = JSON.stringify(msg);
        alert(s);
        ws.send(s);
    }
</script>
</head>
<body>
<button onclick='send()'>Send</button>
</body>
</html>

client.go

package main

import (
    "log"
    "net/rpc/jsonrpc"
    "github.com/gorilla/websocket"
)

func main() {
    ws, _, err := websocket.DefaultDialer.Dial("ws://localhost:8080/ws", nil)
    if err != nil {
        log.Fatal("dial:", err)
    }
    defer ws.Close()

    client := jsonrpc.NewClient(ws.UnderlyingConn())

    req := "hello"
    var res string
    err = client.Call("Service.Echo", &req, &res)
    if err != nil {
        log.Fatal("Service.Echo error:", err)
    }
    log.Printf("Service.Echo: req:%s res:%s", req, res)
}

你知道问题可能是什么吗?

非常感谢。

祝好!

英文:

I have a WebSocket JSON-RPC server example that I want to use from a browser. When you access the URL "http:localhost:8080", the browser opens the WebSocket connection properly. But when the browser sends the WebSocket request, the server closes the WebSocket connection. I can't even see a trace of the RPC method being called on the server.

However, calling the server from a Go client works perfectly.

<!-- language-all: lang-js -->

server.go

package main

import (
        &quot;log&quot;
        &quot;net/http&quot;
        &quot;net/rpc&quot;
        &quot;net/rpc/jsonrpc&quot;
        &quot;github.com/gorilla/websocket&quot;
)

type Service struct{}

func (t *Service) Echo(req *string, res *string) error {
        log.Printf(&quot;Service.Echo&quot;)
        *res = *req
        log.Printf(&quot;Service.Echo req:%s res:%s&quot;, *req, *res)
        return nil 
}

var upgrader = websocket.Upgrader{
        ReadBufferSize:  1024,
        WriteBufferSize: 1024,
}

func serveWS(w http.ResponseWriter, r *http.Request) {
        ws, err := upgrader.Upgrade(w, r, nil)
        defer ws.Close()


        if err != nil {
                log.Println(err)
                return
        }   
        jsonrpc.ServeConn(ws.UnderlyingConn())
}

func main() {
        rpc.Register(new(Service))
        http.Handle(&quot;/&quot;, http.FileServer(http.Dir(&quot;web&quot;)))
        http.HandleFunc(&quot;/ws&quot;, serveWS)
        http.ListenAndServe(&quot;:8080&quot;, nil)
}

web/index.html

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;  
&lt;script type=&quot;text/javascript&quot;&gt;
    var ws = new WebSocket(&quot;ws://localhost:8080/ws&quot;);
    ws.onopen = function(ev){
        alert(&quot;open&quot;);
    }
    ws.onmessage = function(ev){
        alert(&quot;message&quot;);
    }
    ws.onclose = function(ev){
        alert(&quot;close&quot;);
    }   
        
    function send() {
        msg = {
                method: &quot;Service.Echo&quot;,
                params: &quot;hello&quot;,
                id: 0
        };
        var s = JSON.stringify(msg);
        alert(s);
        ws.send(s);
    }   
&lt;/script&gt;
&lt;/head&gt; 
&lt;body&gt;          
&lt;button onclick=&#39;send()&#39;&gt;Send&lt;/button&gt;
&lt;/body&gt; 
&lt;/html&gt;

client.go

package main
    
import (
        &quot;log&quot;
        &quot;net/rpc/jsonrpc&quot;
        &quot;github.com/gorilla/websocket&quot;
)
    
func main() {
        ws, _, err := websocket.DefaultDialer.Dial(&quot;ws://localhost:8080/ws&quot;, nil)
        if err != nil {
                log.Fatal(&quot;dial:&quot;, err)
        }
        defer ws.Close()
        
        client := jsonrpc.NewClient(ws.UnderlyingConn())
    
        req := &quot;hello&quot;
        var res string
        err = client.Call(&quot;Service.Echo&quot;, &amp;req, &amp;res)
        if err != nil {
                log.Fatal(&quot;Service.Echo error:&quot;, err)
        }
        log.Printf(&quot;Service.Echo: req:%s res:%s&quot;, req, res)
}

Do you know what the problem could be?

Thank you very much.

Cheers

答案1

得分: 2

当服务器应用程序调用jsonrpc.ServeConn(ws.UnderlyingConn())时,服务器将从WebSocket协议切换到JSON-RPC协议。浏览器继续使用WebSocket协议。连接关闭是因为其中一个对等方在读取其不期望的协议时出现错误。

使用Go客户端应用程序不会出现此问题,因为该应用程序也会从WebSocket协议切换到JSON-RPC协议。

无法从浏览器应用程序访问底层网络连接。

可以使用net/rpc包,并编写使用WebSocket协议的Codec来实现。另一种选择是编写一个适配器,将基于消息的WebSocket API转换为net/rpc/jsonrpc服务器所期望的流。

英文:

When the server application calls jsonrpc.ServeConn(ws.UnderlyingConn())
}
the server is switching from the WebSocket protocol to the JSON-RPC protocol. The browser continues to use the WebSocket protocol. The connection is closed because one of the peers errors out reading a protocol that it does not expect.

The problem does not happen with the Go client application because this application also switches from the WebSocket protocol to the JSON-RPC protocol.

It is not possible to access the underlying network connection from a browser application.

It is possible to use the net/rpc package with Codec written to use the WebSocket protocol. Another option is to write an adaptor to convert the message based WebSocket API to the stream expected by the net/rpc/jsonrpc server.

huangapple
  • 本文由 发表于 2016年4月2日 19:29:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/36372650.html
匿名

发表评论

匿名网友

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

确定