无法将 ESP32 连接到部署到 Heroku 的 websocket 服务器

时间:2021-01-28 05:42:27

标签: node.js http heroku websocket esp32

这是我的 ESP32 代码,

#include <WiFi.h>
#include <WebSocketClient.h>
#include <ArduinoJson.h> 
const char* ssid     = "###";
const char* password = "###";
 
char path[] = "/";
char host[] = "https://hidden-thicket-03510.herokuapp.com";
 
WebSocketClient webSocketClient;
WiFiClient client;

int timer=0;
void connnect(){
   if (client.connect(host,443)) {
    Serial.println("Connected");
  } else {
    Serial.println("Connection failed.");
  }
 
  webSocketClient.path = path;
  webSocketClient.host = host;
  if (webSocketClient.handshake(client)) {
    Serial.println("Handshake successful");
  } else {
    Serial.println("Handshake failed.");
  }
}
void setup() {
  Serial.begin(115200);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
 
  delay(5000);
 
 connnect();

 if (client.connected()) {
   webSocketClient.sendData("Info to be echoed back");
 }
 
}
 
void loop() {
  String data;
  
    if (client.connected()) {

    webSocketClient.getData(data);
    Serial.println(data);
    int data_len = data.length() + 1; 
    char char_array[data_len];
    data.toCharArray(char_array, data_len);
    StaticJsonDocument<1200> doc;

    DeserializationError err=deserializeJson(doc,char_array);

    const char* a=doc["message"];
    
    if (data_len > 1) {
      Serial.print("Received data: ");
      Serial.println(a);
    }
    
  } else {
    Serial.println("Client disconnected.");
    connnect();
  }
 
  delay(3000);
 
}

这是在 Heroku 上运行的服务器代码

var WebSocketServer = require('websocket').server;
var http = require('http');

var server = http.createServer(function(request, response) {
    console.log((new Date()) + ' Received request for ' + request.url);
    response.writeHead(404);
    response.end();
});
let port =process.env.PORT || 5000;
server.listen(port, function() {
    console.log((new Date()) + ' Server is listening on port 5000');
});

wsServer = new WebSocketServer({
    httpServer: server
});
const clients={}
wsServer.on('request', request=> { 
    var connection = request.accept(null, request.origin);
    console.log((new Date()) + ' Connection accepted.');
    
    const clientId=guid();
    clients[clientId]={
        "connection":connection
    };

    // connection.sendUTF("JSON.stringify(payload)")
    connection.on('open',()=>{console.log("opened")})

    connection.on('message', message => {
        console.log(message);
        var a=JSON.stringify({'message':'sdaed'})
        connection.send(a)
        
    });

    connection.on('close', (reasonCode, description) =>{
        console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
    });

    const payload={
        "method":"connect",
        "clientId":clientId
    }
    
    
});



const guid=()=> {
    const s4=()=> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);     
    return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`;
  }


当我在 PC 上本地运行服务器时,ESP32 连接到服务器。但是当我将服务器部署到 Heroku 并尝试连接时,ESP32 握手失败。这是我得到的串行监视器上的输出

Connected
Waiting...
Waiting...
Waiting...
Handshake failed.
Client disconnected.
Connected
Waiting...
Waiting...
Waiting...
Handshake failed.
Client disconnected.
Connected
Waiting...
Waiting...
Waiting...
Waiting...
Waiting...
Handshake failed.

部署到服务器没有问题,因为当我使用 nodejs websocket 客户端(来自 repo 的示例)时,它成功连接到部署的 Heroku 服务器。我已经尝试将端口号更改为 80 并在 Arduino 脚本上使用“http://hidden-thicket-03510.herokuapp.com”,但它仍然不起作用。

为什么我的 ESP32 可以连接到本地运行的服务器,但部署到服务器后无法连接

P.S - 如果您想测试一下,上面的服务器仍在工作。

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

那是因为您要连接到 TLS 端点,但 WiFiClient 类(用于创建底层连接)未实现 TLS。 WebSocketClient 类期望接收一个工作数据管道,但它获得了一个必须设置 TLS 的 TCP 连接。

乐鑫提供了 TCP+TLS 实现 WiFiClientSecure,因此请使用它而不是 WiFiClient。

请注意,与各种桌面操作系统和浏览器不同,ESP 默认不包含任何根证书。因此它无法验证远程服务器并拒绝连接。您必须手动将服务器的证书添加到您的 ESP32 项目 - CA、中间或叶(CA 可能是最佳选择)。项目的 README 中提供了有关如何执行此操作的文档。

要获取与您的服务器关联的证书,我使用 openssl

openssl s_client -showcerts -connect hidden-thicket-03510.herokuapp.com:443

我看到您的 CA 证书可能是名为“DigiCert High Assurance EV Root CA”的证书。复制输出中的最后一个 PEM 块(base64 以 -----BEGIN CERTIFICATE----- 开头并以 -----END CERTIFICATE----- 结尾,包括在内),将其粘贴到文件“ca.pem”并按照说明将其添加到您的 ESP 项目中。< /p>

要验证此文件是 CA 证书,请运行

openssl x509 -in ca.pem -text -noout

输出应包括 Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV Root CA