如何在React Native中实现WebSockets

2,072 阅读9分钟

网络最初是根据请求和响应的原则实现的:客户机发出请求,服务器用适当的响应进行回复。当没有根据客户端请求进行数据操作的要求时,习惯上是提供一个静态页面。

动态页面出现时,我们被引入了GET、POST、PUT和DELETE请求的概念。现在,客户能够通过发送其要求作为参数来要求服务器提供自定义数据。然后,服务器处理该请求并返回一个动态响应。

不过,基本原理还是基于请求和响应:客户端请求,服务器响应,然后关闭连接。

还有一种协议的工作方式不像请求-响应方案,称为WebSockets。在本教程中,我们将向你介绍WebSockets技术和它的一些常见用例。我们将指导你如何通过设计一个消息广播应用在React Native中实现WebSockets。

什么是WebSockets?

WebSockets是一种提供全双工通信的协议,这意味着客户端和服务器通过一个TCP连接保持连接。与请求-响应通信不同,这里的连接不会关闭。

由于它是全双工的,服务器也可以在没有请求的情况下向客户端发送数据。这有助于节省带宽和响应时间。

WebSockets协议以ws:// 开始。对于处理超文本,我们使用http://https://

为什么使用WebSockets?

WebSockets有一系列的应用,但我们主要是在需要由服务器广播或推送数据的情况下使用它们。

例如,一个聊天应用程序的服务器需要在发送者发送消息后立即将其发送给收件人。服务器不能等待客户端请求新消息,所以它使用全双工通信将其推送给客户端。类似地,新闻、贸易矩阵,甚至社交媒体的帖子都是以这种方式推送的。

在WebSockets进入之前,这种结果是可以实现的,但它们是不可靠的,而且效率低下。

例如,许多公司使用长时间的轮询,在这种情况下,浏览器发送请求,但服务器没有回应。连接一直处于活动状态,直到出现连接超时。在此期间,如果服务器有任何信息给客户,它就会作出回应,然后连接就会关闭。一旦连接关闭,无论是由于超时还是由于服务器响应,客户都会再次发送请求。这个过程一直在进行。

另一种方法是以几秒钟的间隔发送AJAX请求--比如三秒钟--并获得服务器响应,这要么是一个有效的消息,要么是空对象。因此,一条新的消息最多可以延迟三秒。这种方法的缺点是,大量的API调用被浪费了,因为服务器没有任何消息可以回应。

如何在React Native中使用WebSockets

在WebSockets的生命周期中,有四个主要功能被执行。它们在应用程序建立连接、接收消息、捕获错误和断开连接时被调用。

让我们放大这些函数。

创建一个WebSockets连接

第一步是与服务器建立一个连接。WebSockets在他们自己的协议上工作,ws://

在React Native中,我们可以用下面的代码创建一个连接。

var ws = new WebSocket('ws://host.com/path');

这里的连接对应的是后台运行的套接字服务

如果服务器接受连接,它将通过调用WebSocket对象上的onopen 函数来通知客户端。

ws.onopen = () => {
  // connection opened
  ws.send('something');  // send a message
};

这就像构造函数。你可以在这个函数中分配资源。此外,如果你需要向服务器发送一些一次性的信息,如用户识别号,你可以在这里进行。

接收信息

在一个请求-响应策略中,客户端在发送的请求中寻找响应。这意味着客户端知道什么时候会从服务器得到数据,所以它保持着处理数据的准备。但在像WebSockets这样的全双工通信中,服务器可以在任何时候发送数据,而不需要征得客户端的同意。

为了处理这种情况,当服务器发送消息时必须调用一个函数。

在React Native中,我们有一个onmessage 函数来处理这个问题。

ws.onmessage = (e) => {
  // a message was received
  console.log(e.data);
};

处理错误

当出现错误时,无论是由于互联网连接不畅还是服务器内部错误,都会调用onerror 函数。

ws.onerror = (e) => {
  // an error occurred
  console.log(e.message);
};

连接关闭

当连接关闭时,无论是服务器还是客户端,onclose 函数被调用。这就像一个析构器,你可以释放分配的资源。

ws.onclose = (e) => {
  // connection closed
  console.log(e.code, e.reason);
};

现在我们已经看到了React Native中WebSockets的完整生命周期,从建立连接到关闭连接。我们可以在单个块中写下所有这些函数,如下所示。

var ws = new WebSocket('ws://host.com/path');

ws.onopen = () => {
  // connection opened
  ws.send('something'); // send a message
};

ws.onmessage = (e) => {
  // a message was received
  console.log(e.data);
};

ws.onerror = (e) => {
  // an error occurred
  console.log(e.message);
};

ws.onclose = (e) => {
  // connection closed
  console.log(e.code, e.reason);
};

WebSockets的例子。消息广播应用

为了展示WebSockets的作用,让我们在Rect Native中创建一个简单的消息广播应用。在我们的演示应用程序中,从一个应用程序发送的消息将被广播到所有连接的应用程序。

我们将在Node.js中开发服务器脚本。下面是WebSockets服务器的代码。

const express = require("express");
const app = express();
const http = require("http");
const WebSocket = require("ws");
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
wss.on("connection", function connection(ws) {
  ws.on("message", function incoming(message, isBinary) {
    console.log(message.toString(), isBinary);
    wss.clients.forEach(function each(client) {
      if (client.readyState === WebSocket.OPEN) {
        client.send(message.toString());
      }
    });
  });
});
app.get("/", (req, res) => {
  res.send("Hello World!");
});
server.listen(8080, () => {
  console.log("Listening to port 8080");
});

你可以在npm repositoriy的ws包中找到这些代码。

记住,你需要保持服务器处于活动状态。否则,客户端将无法连接。

客户端代码

现在我们的服务器已经成功运行,是时候创建我们的React Native应用了。

在顶部,我们将创建一个水平条来显示连接或断开的通知以及错误。在底部,我们将放置一个输入字段和一个提交按钮,通过WebSockets发送消息。中间区域的其余部分将用于显示从服务器上收到的消息列表。

这是一个广播应用,所以从任何设备发送的任何消息都会被广播到所有设备上。

让我们来看看代码。

import * as React from 'react';
import { Text, View, StyleSheet, TextInput, Button, ScrollView } from 'react-native';


export default function App() {
  const [serverState, setServerState] = React.useState('Loading...');
  const [messageText, setMessageText] = React.useState('');
  const [disableButton, setDisableButton] = React.useState(true);
  const [inputFieldEmpty, setInputFieldEmpty] = React.useState(true);
  const [serverMessages, setServerMessages] = React.useState([]);
  var ws = React.useRef(new WebSocket('ws://w567l.sse.codesandbox.io/')).current;


  React.useEffect(() => {
    const serverMessagesList = [];
    ws.onopen = () => {
      setServerState('Connected to the server')
      setDisableButton(false);
    };
    ws.onclose = (e) => {
      setServerState('Disconnected. Check internet or server.')
      setDisableButton(true);
    };
    ws.onerror = (e) => {
      setServerState(e.message);
    };
    ws.onmessage = (e) => {
      serverMessagesList.push(e.data);
      setServerMessages([...serverMessagesList])
    };
  }, [])
  const submitMessage = () => {
    ws.send(messageText);
    setMessageText('')
    setInputFieldEmpty(true)
  }
  return (
    <View style={styles.container}>
      <View style={{
        height: 30,
        backgroundColor: '#eeceff',
        padding: 5
      }}>
        <Text>{serverState}</Text>
      </View>
      <View style={{
        backgroundColor: '#ffeece',
        padding: 5,
        flexGrow: 1
      }}>
        <ScrollView>
          {
            serverMessages.map((item, ind) => {
              return (
                <Text key={ind}>{item}</Text>
              )
            })
          }
        </ScrollView>
      </View>
      <View style={{
        flexDirection: 'row',
      }}>
        <TextInput style={{
            borderWidth: 1,
            borderColor: 'black',
            flexGrow: 1,
            padding: 5,
          }} 
          placeholder={'Add Message'} 
          onChangeText={text => {
            setMessageText(text)
            setInputFieldEmpty(text.length > 0 ? false : true)  
          }}
          value={messageText}
         />
        <Button
         onPress={submitMessage}
         title={'Submit'} 
         disabled={disableButton || inputFieldEmpty}
        />
      </View>

    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#ecf0f1',
    paddingTop: 30,
    padding: 8,
  },

});

简而言之,在React Native应用中实现WebSockets的过程如下。

  1. React Native应用程序创建一个新的WebSockets连接,并将其存储在一个参考变量中。ws
  2. 应用程序的顶部栏显示serverState 变量的值,中间部分显示存储在serverMessages 数组中的文本信息,底部栏有一个输入字段,在messageText 状态变量中存储输入的信息
  3. 提交按钮只有在应用程序成功连接到WebSockets并且输入框中有一些文本时才会被激活。我们使用disableButtoninputFieldEmpty 变量来控制它。当disableButtoninputFieldEmpty 都处于激活状态时,提交按钮将被激活。false
  4. useEffect() 钩子中,我们定义所有的WebSocket函数
  5. 当WebSockets连接被服务器打开时,onopen 函数被调用。这将改变serverState 变量的值为connected to the serverdisableButtonfalse ,因此应用程序的顶部栏显示连接的消息
  6. 当连接关闭时,onclose 函数被调用。这就把serverState 改为disconnected message ,把disableButton 改为true 。在这一点上,即使你在输入框中输入了信息,提交按钮也不再有效,因为我们不能向服务器发送信息。
  7. 如果有一个错误,onerror 函数被调用,并将serverState 改为该特定的错误信息
  8. 当服务器广播消息时,会调用onmessage 函数。这将把收到的消息追加到serverMessages 数组中。
  9. 我们创建了一个submitMessage ,将消息发送到服务器,由服务器广播给所有设备

在这里,我嵌入了这个应用程序的两个实例:一个用于Android,另一个用于iOS。你可以测试一下,从一个设备上发送的消息会在两个设备上显示。验证我们上面嵌入的Node.js服务器是否运行正常,是否处于休眠模式。

如果你在上述设备上遇到问题,你可以运行这里的代码。

总结

在本教程中,我们向你展示了在React Native应用程序中创建WebSockets是多么容易。该代码可以在Android和iOS平台上运行。

我们为这个特定的演示创建了一个简单的广播应用,但还有很大的空间来扩展它。例如,你可以设置ID来区分客户端,并将客户端发送的消息排列在右侧,而将其他所有消息排列在左侧。这将产生一个完美的类似聊天应用程序的外观和感觉。

您还可以创建一个表格,在开始聊天前捕捉细节(如用户的名字),并在收到的消息旁显示该信息。

请在评论中告诉我们你在React Native中使用WebSockets构建了什么样的东西。

The postHow to implement WebSockets in React Nativeappeared first onLogRocket Blog.