如何连接到它反应的 websocket 而不是普通的 javascript?
Posted
技术标签:
【中文标题】如何连接到它反应的 websocket 而不是普通的 javascript?【英文标题】:How do I connect to a websocket it react instead of plain 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
【问题讨论】:
【参考方案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 := &connectionsend: make(chan []byte, 256), ws: ws
s := subscriptionco, 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 := messagemsg, 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)
【讨论】:
以上是关于如何连接到它反应的 websocket 而不是普通的 javascript?的主要内容,如果未能解决你的问题,请参考以下文章
连接到 WebSocket 时如何覆盖 Chrome 中的 Origin 标头?