Dav*_*tti 4 nginx node.js express server-sent-events reactjs
你好,我正在 React 中开发一个 Web 应用程序,它使用 Nginx 从 Express 服务器接收 SSE 数据。
\n\n服务器端JS
\n\nconst express = require(\'express\');\nconst bodyParser = require(\'body-parser\');\nconst cors = require(\'cors\');\nconst crypto = require(\'crypto\');\n\nconst app = express();\n\nvar lastClientRes = null;\nfunction eventsHandler(req, res, next) {\n const headers = {\n \'Content-Type\': \'text/event-stream\',\n \'Connection\': \'keep-alive\',\n \'Cache-Control\': \'no-cache\'\n };\n res.writeHead(200, headers);\n\n const clientId = Date.now();\n const newClient = {\n id: clientId,\n nonce: null,\n cart: null,\n res\n };\n requests.push(newClient);\n\n\n const data = `data: ${JSON.stringify({client: clientId})}\\n\\n`;\n res.write(data);\n\n req.on(\'close\', () => {\n console.log(`${clientId} Connection closed`);\n clients = clients.filter(c => c.id !== clientId);\n });\n}\n\n\nfunction sendEventsToAll(newNest) {\n clients.forEach(c => c.res.write(`data: ${JSON.stringify(newNest)}\\n\\n`))\n}\n\nasync function addCart(req, res) {\n const newCart = req.body;\n\n\n requests.forEach(r => {\n if(newCart.client == r.id){\n var nonce = crypto.randomBytes(16).toString(\'base64\');\n r.nonce = nonce;\n r.cart = newCart.cart;\n r.res.write(`data: ${JSON.stringify({nonce: nonce})}\\n\\n`);\n }\n\n })\n}\n\nasync function addCart(req, res) {\n const newCart = req.body;\n\n\n requests.forEach(r => {\n if(newCart.client == r.id){\n var nonce = crypto.randomBytes(16).toString(\'base64\');\n r.nonce = nonce;\n r.cart = newCart.cart;\n r.res.write(`data: ${JSON.stringify({nonce: nonce})}\\n\\n`);\n }\n\n })\n}\n\nasync function confirmCart(req, res){\n var nonce = req.body.nonce;\n var found = -1;\n requests.forEach((item, i) => {\n if(item.nonce == nonce){\n found = i;\n return;\n }\n });\n\n\n if(found)\n {\n console.log("OK");\n requests[found].res.write(`data: ${JSON.stringify({confirm: true})}\\n\\n`);\n }\n}\n\napp.use(cors());\napp.use(bodyParser.json());\napp.use(bodyParser.urlencoded({extended: false}));\n\napp.post(\'/addCart\', addCart);\napp.post(\'/confirmCart\', confirmCart);\napp.get(\'/events\', eventsHandler);\napp.get(\'/status\', (req, res) => res.json({clients: clients.length}));\n\nconst PORT = 3001;\n\nlet requests= [];\nlet clients = [];\nlet nests = [];\n\napp.listen(PORT, () => console.log(`SSE service listening on port ${PORT}`));\nRun Code Online (Sandbox Code Playgroud)\n\n索引:JS
\n\nimport React from \'react\';\nimport ReactDOM from \'react-dom\';\nimport axios from \'axios\';\n\nclass App extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n jsonCart: "",\n cartNonce: "",\n clientId: "",\n cartConfirmed: false,\n cart: Array(),\n timerId: null,\n listening: false,\n cartConfermato: ""\n };\n }\n\n buy(){\n if (!this.state.listening) {\n const events = new EventSource(\'https://api.myDomain.com/events\', );\n events.onmessage = (event) => {\n const parsedData = JSON.parse(event.data);\n\n console.log(event.data);\n\n if(parsedData.client != null)\n {\n this.setState({\n clientId: parsedData.client,\n });\n this.sendCart();\n }\n\n if(parsedData.nonce != null)\n this.setState({\n cartNonce: parsedData.nonce,\n });\n\n if(parsedData.confirm == true)\n this.setState({\n cartNonce: "",\n cartConfermato: "Il carrello \xc3\xa8 stato confermato!"\n });\n };\n\n this.setState({\n listening: true\n });\n }\n }\n\n sendCart(){\n var cart = JSON.stringify(this.state.cart.slice());\n this.setState({\n jsonCart: cart\n });\n\n axios.post(`https://api.myDomain.com/addCart`, {client: this.state.clientId, cart: cart});\n }\n\n\n *** ... ***\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n\nconst events = new EventSource(\' https://api.myDomain.com/events \', );
\n\naxios.post(
\nhttps://api.myDomain.com/addCart, {client:\n this.state.clientId, cart: cart});
在 http 中,一切工作正常,但如果我设置 https 使用 certbot 生成证书,我将不再从 Express 服务器接收“事件”。
\n\nchrome 控制台中出现的唯一错误是这个
\n\n我用我的域名替换了 sub.domain
\n\n这些错误会在第一次请求后几分钟出现
\n\nGET https://sub.domain.com/events net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)\n2sub.domain.com/addCart:1 POST https://sub.domain.com/addCart 504 (Gateway Time-out)\n(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.\ncreateError.js:16 Uncaught (in promise) Error: Network Error\n at e.exports (createError.js:16)\n at XMLHttpRequest.p.onerror (xhr.js:83)\ne.exports @ createError.js:16\np.onerror @ xhr.js:83\nerror (async)\n(anonymous) @ xhr.js:80\ne.exports @ xhr.js:12\ne.exports @ dispatchRequest.js:50\nPromise.then (async)\nu.request @ Axios.js:61\nr.forEach.u.<computed> @ Axios.js:86\n(anonymous) @ bind.js:9\nvalue @ index.js:156\nstate.listening.EventSource.onmessage @ index.js:121\nindex.js:114 {"client":1579885346578}\nindex.js:150 send\nsub.domain.com/events:1 GET https://sub.domain.com/events net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)\n2sub.domain.com/addCart:1 POST https://sub.domain.com/addCart net::ERR_ABORTED 504 (Gateway Time-out)\nRun Code Online (Sandbox Code Playgroud)\n
小智 6
正如 Darren Cook 所描述的,您 需要禁用服务器端的缓冲。添加“X-Accel-Buffering”参数并将其在响应标头中设置为“no”为我解决了这个问题。
const headers = {
'Content-Type': 'text/event-stream',
'Connection': 'keep-alive',
'Cache-Control': 'no-cache',
'X-Accel-Buffering': 'no'
};Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7948 次 |
| 最近记录: |