【问题标题】:How do I connect to a websocket it react instead of plain javascript?如何连接到它反应的 websocket 而不是普通的 javascript?
【发布时间】:2020-06-25 16:04:10
【问题描述】:

我想创建一个与 websocket 建立连接的组件。

我有一个当前创建 websocket 连接的 go 后端。

    r.LoadHTMLFiles("index.html")
    r.GET("/room/:roomId", func(c *gin.Context) {
        c.HTML(200, "index.html", nil)
    })
    r.GET("/ws/:roomId", func(c *gin.Context) {
        roomID := c.Param("roomId")
        handler.OpenWebSocket(c.Writer, c.Request, roomID)
    })

这是我的html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Chat Example</title>
    <script type="text/javascript">
        window.onload = function () {
            let conn;
            let msg = document.getElementById("msg");
            let log = document.getElementById("log");

            function appendLog(item) {
                let doScroll = log.scrollTop > log.scrollHeight - log.clientHeight - 1;
                log.appendChild(item);
                if (doScroll) {
                    log.scrollTop = log.scrollHeight - log.clientHeight;
                }
            }

            document.getElementById("form").onsubmit = function () {
                if (!conn) {
                    console.log("hello1")
                    return false;
                }
                if (!msg.value) {
                    console.log("hello2")

                    return false;
                }
                conn.send(msg.value);
                msg.value = "";
                return false;
            };

            if (window["WebSocket"]) {
                const params = window.location.href.split("/");
                const roomId = params[params.length - 1];
                const url ="ws://" + document.location.host + "/ws/" + 99
                conn = new WebSocket(url);
                console.log(url)
                conn.onclose = function (evt) {
                  console.log("i was closed")
                    let item = document.createElement("div");
                    item.innerHTML = "<b>Connection closed.</b>";
                    appendLog(item);
                };
                conn.onmessage = function (evt) {
                    let messages = evt.data.split('\n');
                    console.log(messages)
                    for (let i = 0; i < messages.length; i++) {
                        let item = document.createElement("div");
                        item.innerText = messages[i];
                        appendLog(item);
                    }
                };
            } else {
                let item = document.createElement("div");
                item.innerHTML = "<b>Your browser does not support WebSockets.</b>";
                appendLog(item);
            }
        };
    </script>
    <style type="text/css">
                

        body {
            overflow: hidden;
            padding: 0;
            margin: 0;
            width: 100%;
            height: 100%;
            background: gray;
        }

        #log {
            background: white;
            margin: 0;
            padding: 0.5em 0.5em 0.5em 0.5em;
            position: absolute;
            top: 0.5em;
            left: 0.5em;
            right: 0.5em;
            bottom: 3em;
            overflow: auto;
        }

        #form {
            padding: 0 0.5em 0 0.5em;
            margin: 0;
            position: absolute;
            bottom: 1em;
            left: 0px;
            width: 100%;
            overflow: hidden;
        }

    </style>
</head>
<body>
<div id="log"></div>
<form id="form">
    <input type="text" id="msg" size="64" autofocus/>
    <input type="submit" value="Send"/>
</form>
</body>
</html>

这很好,如果我访问 http://localhost:8080/room/12 然后我可以访问聊天,一切都很好。但是,当我尝试使用 react 和 nextjs 建立连接时,我得到了

WebSocket connection to 'ws://localhost:8080/ws' failed: Error during WebSocket handshake: Unexpected response code: 404

这是我的反应页面。

import React, {useState, useEffect, useRef } from 'react'

import Head from 'next/head'

import { useRouter } from 'next/router'
import { initializeApollo, useApollo } from '@/utils/apollo'
import { ProfileDataQuery } from '@/gql'

import { UserData } from '@/types'
import { NextPageContext } from 'next'

type ProfilePageProps = {
  initialApolloState: any
}

const ProfilePage: React.FunctionComponent<ProfilePageProps> = ({ initialApolloState }) => {
  const apolloClient = useApollo(initialApolloState)
  const router = useRouter()
  const [isPaused, setPause] = useState(false)

  useEffect(() => {
    ws.current = new WebSocket("ws://localhost:8080/ws");
    ws.current.onopen = () => console.log("ws opened");
    ws.current.onclose = () => console.log("ws closed");

    return () => {
      ws.current.close()
    }
  }, []);
  useEffect(() => {
    if (!ws.current) return;

    ws.current.onmessage = e => {
        if (isPaused) return;
        const message = JSON.parse(e.data);
        console.log("e", message);
    };
}, [isPaused]);
  const data = apolloClient.readQuery({
    query: ProfileDataQuery,
    variables: {
      uuid: router.query.uuid
    }
  })
  console.log(data)

  const userData: UserData = data.Users[0]
  const followers: UserData[] = data.followers
  const following: UserData[] = data.following
  const ws = useRef(null)
  
  return (
    <div className="main flex flex-col">
      <Head>
        <title>{ userData.username } - Omiran</title>
      </Head>
      <div className="flex-grow"/>
      <div className="flex flex-col border border-gray-500 rounded-lg w-11/12 md:w-4/5 p-5 mx-auto">
        <div className="flex flex-row items-center w-full">
          <img
            className="rounded-full mr-6"
            src={userData.profilePicture}
            alt={userData.username}
            height={100}
            width={100}
          />
          <div className="flex flex-col">
            <h1 className="text-xl sm:text-2xl md:text-3xl text-left">{userData.username}</h1>
            <div className="flex flex-row">
              <span className="text-sm mr-3">
                <b>{followers.length}</b> Followers
              </span>
              <span className="text-sm">
                <b>{following.length}</b> Following
              </span>
            </div>
          </div>
          <div className="flex-grow" />
          <button className="btn btn-orange">{true ? 'Edit Profile' : 'Follow'}</button>
        </div>
      </div>
      <div className="flex-grow-3"/>
    </div>
  )
}

export async function getServerSideProps(context: NextPageContext) {
  const { uuid } = context.query

  const apolloClient = initializeApollo()

  await apolloClient
    .query({
      query: ProfileDataQuery,
      variables: {
        uuid: String(uuid)
      }
    })

  return {
    props: {
      initialApolloState: apolloClient.cache.extract(),
    },
  }
}

export default ProfilePage

【问题讨论】:

    标签: reactjs websocket next.js


    【解决方案1】:

    我必须 CheckOrigin 以允许来自前端的连接:

    var upgrader = websocket.Upgrader{
        ReadBufferSize:  1024,
        WriteBufferSize: 1024,
        CheckOrigin: func(r *http.Request) bool {
            return r.Header.Get("Origin") == "http://localhost:3000" || r.Header.Get("Origin") == "http://localhost:8080"
        },
    }
    
    

    这是上下文的整个文件:

    package handler
    
    import (
        "log"
        "net/http"
        "time"
    
        "github.com/gorilla/websocket"
    )
    
    const (
        // Time allowed to write a message to the peer.
        writeWait = 10 * time.Second
    
        // Time allowed to read the next pong message from the peer.
        pongWait = 60 * time.Second
    
        // Send pings to peer with this period. Must be less than pongWait.
        pingPeriod = (pongWait * 9) / 10
    
        // Maximum message size allowed from peer.
        maxMessageSize = 512
    )
    
    //H is my connection
    var H = hub{
        broadcast:  make(chan message),
        register:   make(chan subscription),
        unregister: make(chan subscription),
        rooms:      make(map[string]map[*connection]bool),
    }
    
    type hub struct {
        rooms      map[string]map[*connection]bool
        broadcast  chan message
        register   chan subscription
        unregister chan subscription
    }
    
    type message struct {
        data []byte
        room string
    }
    
    type subscription struct {
        conn *connection
        room string
    }
    
    type connection struct {
        ws   *websocket.Conn
        send chan []byte
    }
    
    //OpenWebSocket opens a connection to our nice websocket
    func OpenWebSocket(w http.ResponseWriter, r *http.Request, roomID string) {
        ws, err := upgrader.Upgrade(w, r, nil)
        if err != nil {
            log.Println(err.Error())
            return
        }
        co := &connection{send: make(chan []byte, 256), ws: ws}
        s := subscription{co, roomID}
        H.register <- s
        go s.writePump()
        go s.readPump()
    }
    
    var upgrader = websocket.Upgrader{
        ReadBufferSize:  1024,
        WriteBufferSize: 1024,
        CheckOrigin: func(r *http.Request) bool {
            return r.Header.Get("Origin") == "http://localhost:3000" || r.Header.Get("Origin") == "http://localhost:8080"
        },
    }
    
    func (c *connection) write(mt int, payload []byte) error {
        c.ws.SetWriteDeadline(time.Now().Add(writeWait))
        return c.ws.WriteMessage(mt, payload)
    }
    
    func (s subscription) readPump() {
        c := s.conn
        defer func() {
            H.unregister <- s
            c.ws.Close()
        }()
        c.ws.SetReadLimit(maxMessageSize)
        c.ws.SetReadDeadline(time.Now().Add(pongWait))
        c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
        for {
            _, msg, err := c.ws.ReadMessage()
            if err != nil {
                if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
                    log.Printf("error: %v", err)
                }
                break
            }
            m := message{msg, s.room}
            H.broadcast <- m
        }
    }
    
    func (s *subscription) writePump() {
        c := s.conn
        ticker := time.NewTicker(pingPeriod)
        defer func() {
            ticker.Stop()
            c.ws.Close()
        }()
        for {
            select {
            case message, ok := <-c.send:
                if !ok {
                    c.write(websocket.CloseMessage, []byte{})
                    return
                }
                if err := c.write(websocket.TextMessage, message); err != nil {
                    return
                }
            case <-ticker.C:
                if err := c.write(websocket.PingMessage, []byte{}); err != nil {
                    return
                }
            }
        }
    }
    
    func (H *hub) Run() {
        for {
            select {
            case s := <-H.register:
                connections := H.rooms[s.room]
                if connections == nil {
                    connections = make(map[*connection]bool)
                    H.rooms[s.room] = connections
                }
                H.rooms[s.room][s.conn] = true
            case s := <-H.unregister:
                connections := H.rooms[s.room]
                if connections != nil {
                    if _, ok := connections[s.conn]; ok {
                        delete(connections, s.conn)
                        close(s.conn.send)
                        if len(connections) == 0 {
                            delete(H.rooms, s.room)
                        }
                    }
                }
            case m := <-H.broadcast:
                connections := H.rooms[m.room]
                for c := range connections {
                    select {
                    case c.send <- m.data:
                    default:
                        close(c.send)
                        delete(connections, c)
                        if len(connections) == 0 {
                            delete(H.rooms, m.room)
                        }
                    }
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-23
      • 2021-09-30
      • 2021-10-29
      • 2017-08-10
      • 1970-01-01
      • 1970-01-01
      • 2019-03-08
      • 2019-07-22
      相关资源
      最近更新 更多