当前位置: 首页 > 知识库问答 >
问题:

SSL/HTTPS服务器发送事件(SSE)问题

黎承颜
2023-03-14

您好,我正在React中开发一个web应用程序,它使用Nginx从Express服务器接收SSE数据。

JS服务器

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const crypto = require('crypto');

const app = express();

var lastClientRes = null;
function eventsHandler(req, res, next) {
  const headers = {
    'Content-Type': 'text/event-stream',
    'Connection': 'keep-alive',
    'Cache-Control': 'no-cache'
  };
  res.writeHead(200, headers);

  const clientId = Date.now();
  const newClient = {
    id: clientId,
    nonce: null,
    cart: null,
    res
  };
  requests.push(newClient);


  const data = `data: ${JSON.stringify({client: clientId})}\n\n`;
  res.write(data);

  req.on('close', () => {
    console.log(`${clientId} Connection closed`);
    clients = clients.filter(c => c.id !== clientId);
  });
}


function sendEventsToAll(newNest) {
  clients.forEach(c => c.res.write(`data: ${JSON.stringify(newNest)}\n\n`))
}

async function addCart(req, res) {
  const newCart = req.body;


  requests.forEach(r => {
    if(newCart.client == r.id){
      var nonce = crypto.randomBytes(16).toString('base64');
      r.nonce = nonce;
      r.cart = newCart.cart;
      r.res.write(`data: ${JSON.stringify({nonce: nonce})}\n\n`);
    }

  })
}

async function addCart(req, res) {
  const newCart = req.body;


  requests.forEach(r => {
    if(newCart.client == r.id){
      var nonce = crypto.randomBytes(16).toString('base64');
      r.nonce = nonce;
      r.cart = newCart.cart;
      r.res.write(`data: ${JSON.stringify({nonce: nonce})}\n\n`);
    }

  })
}

async function confirmCart(req, res){
  var nonce = req.body.nonce;
  var found = -1;
  requests.forEach((item, i) => {
    if(item.nonce == nonce){
      found = i;
      return;
    }
  });


  if(found)
    {
      console.log("OK");
      requests[found].res.write(`data: ${JSON.stringify({confirm: true})}\n\n`);
    }
}

app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

app.post('/addCart', addCart);
app.post('/confirmCart', confirmCart);
app.get('/events', eventsHandler);
app.get('/status', (req, res) => res.json({clients: clients.length}));

const PORT = 3001;

let requests= [];
let clients = [];
let nests = [];

app.listen(PORT, () => console.log(`SSE service listening on port ${PORT}`));

索引:JS

import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';

class App extends React.Component {
  constructor(props) {
     super(props);
     this.state = {
       jsonCart: "",
       cartNonce: "",
       clientId: "",
       cartConfirmed: false,
       cart: Array(),
       timerId: null,
       listening: false,
       cartConfermato: ""
     };
   }

   buy(){
     if (!this.state.listening) {
        const events = new EventSource('https://api.myDomain.com/events', );
        events.onmessage = (event) => {
          const parsedData = JSON.parse(event.data);

          console.log(event.data);

          if(parsedData.client != null)
          {
            this.setState({
              clientId: parsedData.client,
            });
            this.sendCart();
          }

          if(parsedData.nonce != null)
            this.setState({
              cartNonce: parsedData.nonce,
            });

          if(parsedData.confirm == true)
            this.setState({
              cartNonce: "",
              cartConfermato: "Il carrello è stato confermato!"
            });
        };

        this.setState({
          listening: true
        });
      }
   }

   sendCart(){
     var cart = JSON.stringify(this.state.cart.slice());
     this.setState({
       jsonCart: cart
     });

     axios.post(`https://api.myDomain.com/addCart`, {client: this.state.clientId, cart: cart});
   }


   *** ... ***

const events=新事件源('https://api.myDomain.com/events', );

axios。post(<代码>https://api.myDomain.com/addCart,{客户端:this.state.clientId,购物车:cart});

在http中,一切都能正常工作,但如果我使用certbot设置https生成证书,我将不再从express服务器接收“事件”。

chrome控制台中出现的唯一错误是

我用我的域替换了sub.domain

这些错误出现在第一个请求后几分钟

GET https://sub.domain.com/events net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)
2sub.domain.com/addCart:1 POST https://sub.domain.com/addCart 504 (Gateway Time-out)
(index):1 Access to XMLHttpRequest at 'https://sub.domain.com/addCart' from origin 'https://example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
createError.js:16 Uncaught (in promise) Error: Network Error
    at e.exports (createError.js:16)
    at XMLHttpRequest.p.onerror (xhr.js:83)
e.exports @ createError.js:16
p.onerror @ xhr.js:83
error (async)
(anonymous) @ xhr.js:80
e.exports @ xhr.js:12
e.exports @ dispatchRequest.js:50
Promise.then (async)
u.request @ Axios.js:61
r.forEach.u.<computed> @ Axios.js:86
(anonymous) @ bind.js:9
value @ index.js:156
state.listening.EventSource.onmessage @ index.js:121
index.js:114 {"client":1579885346578}
index.js:150 send
sub.domain.com/events:1 GET https://sub.domain.com/events net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)
2sub.domain.com/addCart:1 POST https://sub.domain.com/addCart net::ERR_ABORTED 504 (Gateway Time-out)

共有1个答案

齐典
2023-03-14

正如Darren Cook在这里所描述的,您需要禁用服务器端的缓冲。在响应标头中添加“X-Accel-Buffering”参数并将其设置为“no”,为我解决了这个问题。

const headers = {
    'Content-Type': 'text/event-stream',
    'Connection': 'keep-alive',
    'Cache-Control': 'no-cache',
    'X-Accel-Buffering': 'no'
  };
 类似资料:
  • 我有一个ASP。net core 3.1服务器项目,它有一个非常简单的API发送单向服务器发送事件(SSE),如下所示: 现在,我想通过C#UWP客户端接收这些事件。很遗憾,我只收到第一个事件: 如何在UWP中创建行为以始终监听该连接并接收我可以进一步处理的事件?

  • 我无法理解HTML5s服务器发送的事件是否真的适合ReST体系结构。我知道并非HTML5/HTTP的所有方面都需要适合ReST架构。但我想从专家那里知道HTTP的哪一半是SSE(ReSTful的一半还是另一半!)。 一种观点是它是ReSTful的,因为客户端向服务器发出了一个“初始”HTTP GET请求,其余的只能看作是不同内容类型的部分内容响应(“文本/事件流”) 发送的请求不知道有多少响应将作

  • 我想要实现的是: user1向服务器发送消息(一个简单的POST请求) 服务器部分是(events.php) 我在(true)时尝试了无限循环以避免3秒的轮询。我也尝试过没有那个无限循环。只有发送消息的用户收到事件。 我理解这种做法并不好。但是,将SSE用于聊天应用程序的最佳实践是什么? 如何向所有用户发送事件?

  • 我正在尝试使用泽西岛的JavaScript SSE。我的资源中有以下代码。我在Java7和Tomcat 7上托管。我没有收到任何错误。但我也没有在页面上看到数据。 我调用发布数据。它确实显示信息。但客户什么都没有。在Firefox中,我确实看到事件多次触发。 这是我使用的参考。https://jersey.java.net/documentation/latest/sse.html 我的Index

  • 整个应该由管理(其中大多数请求与业务相关),还是应该由某个完全专用于处理的管理?目前,所有业务请求和SSE事件都由处理。 如何在集群环境中应用主动-主动模式(=master-master),其中请求在实例之间随机路由? 如果您有更多有用的信息(和注意事项),请随时分享!

  • 使用系统将“服务器发送事件(SSE)样式”事件流式传输到F#中的前端的轻量级方式是什么。网Http库?我了解事件流格式(例如,这个PHP示例代码),但我正在寻求一些指导,以便在服务器端F#应用程序(我在.Net Framework 4.8上)中实现流部分。