首页 > 解决方案 > 如何防止 Apache 服务器和 Node Express 之间的 HTTPS 错误?

问题描述

我将一台旧笔记本电脑改用于运行 Ubuntu Server 18.04。在我的本地网络上,我给这台笔记本电脑一个固定的 IP 192.168.0.36,这样我就可以从我的主机轻松地通过 SSH 连接到它。

我在这台机器上使用 Apache 服务器来托管一个用 React 编写的网站(单页应用程序是使用构建的npm run build,然后复制到 /var/www/html/)。

同样在笔记本电脑上,我运行了一个 Express 服务器,侦听端口 3305(运行 using node index.js),该服务器与本地 MariaDb RDBMS 实例接口,并在调用时将 JSON 中继回网站。

当我在家中执行此操作时,我正在使用 noip.com 为我提供一个不会在每次我的 ISP 动态更改我的 IP 时更改的 URL。

这一切在 http 下都可以正常工作;但是我希望添加 https 加密,因此使用 LetsEncrypt 的 certbot 将证书添加到我的 Apache 配置中。

不幸的是,现在当我查看我的 React 页面的 https 版本时,没有从数据库中提取任何数据,并且浏览器给了我以下错误:

混合内容:“ https://xxxx.hopto.org ”页面通过 HTTPS 加载,但请求了不安全的资源“ http://192.168.0.36:3305/contract/ ”。此请求已被阻止;内容必须通过 HTTPS 提供。

这很简单——但也令人困惑。侦听端口 3305 的 Express 服务器位于本地计算机上运行的 Apache 之后,因此暗示“值得信赖”。

我很确定问题归结为我如何尝试连接我的 React 应用程序和这个 Express 服务器,它是这样完成的:

App.js(反应网站)

getContract = _ => {
        fetch('http://192.168.0.36:3305/contract/')
            .then(response => response.json())
            .then(response => this.setState({ contract_list: response.data }))
            .catch(err => console.error(err))
    }

index.js(节点快递服务器)

const app = express();

const connection = mysql.createConnection({
    host: config.host,
    user: config.user,
    password: config.password,
    database: config.database
});
app.use(cors());
app.get('/', (req,res) => {
    res.send('go to /contract to see contracts')
});
const SELECT_ALL_CONTRACT_QUERY = 'SELECT * FROM contract';
app.get('/contract', (req, res) => {
    connection.query(SELECT_ALL_CONTRACT_QUERY, (err, results) => {
        if(err) {
            return res.send(err)
        }
        else {
            return res.json({
                data: results
            })
        }
    });
});
app.listen(3305, () => {
    console.log('Db server listening on port 3305')
});

我试图更改 App.js 以便从中获取,http://localhost:3305/contract但这根本无法连接。我也尝试让 Express 服务器提供 https,但这涉及自签名证书,这只会导致不同的错误。

我的预感是我需要深入了解我的 Apache 配置并让它知道它正在查看本地机器而不是外部机器,但我对此没有任何经验......

感谢任何帮助。

标签: node.jsapacheexpresshttps

解决方案


经过大量阅读后,我找到了答案,它确实存在于 Apache 配置中:

1.修改App.js fetch为相对链接

使用我上面的代码示例:

App.js(反应网站)

getContract = _ => {
        fetch('/api/contract/')
            .then(response => response.json())
            .then(response => this.setState({ contract_list: response.data }))
            .catch(err => console.error(err))
    }

然后它在引用 URL 的末尾被分块,所以如果你从https://example.org调用它,那么它指向的 URL(在上面的例子中)是https://example.org/api/contract/ . 有趣的是,是否将反斜杠放在api前面似乎并没有什么不同,但我认为这样更有意义。

2.在Apache中安装需要的模块

在命令行输入:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_html

3.修改Apache配置

在两个文件/etc/apache2/sites-enabled/000-default.conf/etc/apache2/sites-enabled/000-default-le-ssl.conf添加以下文本(在<VirtualHost...>标签内) :

ProxyPass /.well-known/ !
ProxyPass /api http://127.0.0.1:3305
ProxyPassReverse /api http://127.0.0.1:3305
ProxyPreserveHost On

第一个文件(000-default.conf)将调用重定向到http(即端口80),第二个文件(000-default-le-ssl.conf)重定向到https(即端口443)。不确定这些是所有 Apache 设置的配置文件,但它们对我有用。

这告诉 Apache 以/api结尾的 URL 的任何传入流量都应发送到 Express 正在侦听的任何端口(在我的示例中为 3305)上的 localhost(在我的情况下为 127.0.0.1)。

4.重启阿帕奇

sudo systemctl restart apache2


现在,一旦您对系统管理员之神进行了任何您认为合适的仪式,请尝试使用 URL,它应该可以工作...

虽然这是几个来源的组合,但最有用的是通过 Apache 代理节点应用程序


推荐阅读