簡體   English   中英

帶有Express / Apache2 / SSL的Socket.IO

[英]Socket.IO with Express/Apache2/SSL

好吧,我幾乎搜索了我在SO和其他地方找到的關於這個的每一個問題/答案都無濟於事。 所以,我想我會發布這個,看看是否有人有指示我的方向。

安裝程序

我在單獨的子域上有一個React應用程序和Node / Express API。 React應用程序位於www.domain.com,API位於api.domain.com。 React應用程序使用Express應用程序公開的端點(api.domain.com/endpoint等)。

此外,Express API使用Socket.io進行實時通信,並在與API本身相同的端口上公開。

所有這些都由Apache2提供。

相關代碼樣本

我的根Express文件(index.js):

const app = require('express', '4.16.4')();
const bodyParser = require('body-parser');
const cors = require('cors');
const http = require('http').createServer(app);
const io = require('socket.io')(http);
require('./sockets/chat')(io);

const db = require('./services/db.service');

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

const projects = require('./routes/projects');
const assets = require('./routes/assets');

app.use('/projects', projects);
app.use('/assets', assets);

// Test API endpoint
app.get('/test', (req, res) => {
  res.send('You got me');
});

db.connect();

http.listen(4002, () => {
  console.log('API is ready on 4002');
});

/sockets/chat ,導入上面的文件:

const Message = require('../models/message.model');

module.exports = (io) => {
  io.on('connection', (socket) => {
    socket.on('message', async ({ asset, from, body }) => {
      const msg = new Message({
        asset,
        from,
        body,
      });
      const message = await msg.save();
      io.emit('message', message);
    });
  });
};

使用Socket.io處理接口的React Chat組件:

import React, { Component } from 'react';
import ChatMessage from '../ChatMessage';
import { Auth0Lock } from '../Auth';
import socketIOClient from 'socket.io-client';
import MessageService from '../../services/message.service';
import { apiUrl, loginCallback } from '../../config';

require('./styles.scss');

class Chat extends Component {
  constructor(props) {
    super(props);
    this.state = {
      messages: [],
    }
  }

  componentDidMount() {
    MessageService.getAssetMessages(this.props.assetId)
      .then((messages) => {
        this.setState({ messages })
      })
      .catch((e) => console.log(e));

    this.socket = socketIOClient(apiUrl, {transports: ['websocket']}); 
    this.socket.on('message', (message) => {
      this.setState({
        messages: [
          ...this.state.messages,
          message,
        ],
      });
    });
    this.socket.on('connect_error', (err) => {
      console.log('SocketIO connection error:', err);
    });
  }

位於API前面的Apache2配置(在子域上):

# Added to mitigate CVE-2017-8295 vulnerability
UseCanonicalName On
<VirtualHost *:80>
        ServerName api.reviewcycle.io

        RewriteCond %{SERVER_NAME} =api.reviewcycle.io
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=301]

        ErrorLog ${APACHE_LOG_DIR}/error-reviewcycle-api.log
</VirtualHost>

<VirtualHost *:443>
        ServerName api.reviewcycle.io

        <Proxy *>
                Order allow,deny
                Allow from all
        </Proxy>

        RewriteEngine On
        RewriteCond %{REQUEST_URI}      ^/socket.io/            [NC]
        RewriteCond %{QUERY_STRING}     transport=websocket     [NC]
        RewriteRule /(.*)               wss://localhost:4002/$1 [P,L]

        SSLEngine On
        SSLCertificateFile /etc/cloudflare/reviewcycle.io.pem
        SSLCertificateKeyFile /etc/cloudflare/reviewcycle.io.key

        ProxyPass / http://localhost:4002/
        ProxyPassReverse / http://localhost:4002/
</VirtualHost>

問題

當應用程序加載,並且模塊嘗試連接到Socket.io時,它會失敗,如下所示:

在此輸入圖像描述

至於網絡請求的詳細信息:

在此輸入圖像描述

我幾乎嘗試了所有可能的事情,包括對Apache配置的一系列更改。 我覺得在某個地方,Apache沒有正確地將請求代理到Express,但我不確定。

如果有人看到任何看起來不對勁的東西,我會非常感謝你的幫助! 也很樂意提供跟蹤這一個可能需要的任何其他信息!

TIA!

事實證明,答案非常簡單。

Apache配置中的這一行: RewriteRule /(.*) wss://localhost:4002/$1 [P,L] ,需要具有不同的協議。 由於與API的內部連接不是通過SSL,因此將其更改為ws://最終會解決問題。

如果有其他人偶然發現這一點,希望它有所幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM