node.js - 如何防止 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 配置并让它知道它正在查看本地机器而不是外部机器,但我对此没有任何经验......
感谢任何帮助。
解决方案
经过大量阅读后,我找到了答案,它确实存在于 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 代理节点应用程序。
推荐阅读
- excel - 循环内的运行时错误 91(对象变量或未设置块变量),但代码在其外工作
- ansible - Ansible-Playbook:错误消息“找不到任何要使用的 pip3。需要安装 pip”
- pandas - 使用自己的计算熊猫创建距离矩阵
- java - 在构造函数中使用多捕获异常类型
- c# - 获取所有公共静态方法返回一个空列表
- symfony - Symfony 4 EntityManager 多数据库
- python - 检查父字典是否不为空并检索嵌套字典的值
- javascript - 自动生成 GraphQL API 接口
- php - PHP DOMDocument日文字符编码问题
- r - R - 一个图中的多个图形,但图形重叠部分的透明度不起作用