angular - (未知 url)的 Http 失败响应 - Docker 上的 Angular Universal(SSL)
问题描述
仅当 api 为 HTTPS 时才会出现该错误。测试站点托管在 Digital Ocean 上。但以下设置在我的本地(MAC Os)上使用自签名证书。
我尝试过的事情:
- 在 digitalocean 中禁用防火墙(sudo ufw disable)
- 节点 SSL 验证已禁用 ( NODE_TLS_REJECT_UNAUTHORIZED=0 )
- 没有 cors 问题,我已经允许任何来自 api 的客户端
下面是我的 docker compose 设置
- web - 这是 nginx 容器
- laravel - 这是一个 api
- angualr - 从 Web 使用 api 的 Angular 通用
- 数据库 - mariadb 数据库
码头工人-compose.yml
version: '3'
services:
laravel:
build: ./laravel/docker/php
depends_on:
- database
expose:
- 9000
volumes:
- ./laravel:/var/www/laravel
- $HOME/.composer/:$HOME/.composer/
- ./laravel/docker/php/php-custom.ini:/usr/local/etc/php/conf.d/php-custom.ini
angular:
build: ./angular
expose:
- 9000
volumes:
- ./angular:/var/www/angular:rw
depends_on:
- laravel
links:
- laravel:laravel
web:
build: ./nginx
volumes:
- ./:/var/www/
- ./dh-param/dhparam-2048.pem:/etc/ssl/certs/dhparam-2048.pem:ro
- /docker-volumes/etc/letsencrypt/live/fabivo.com/fullchain.pem:/etc/letsencrypt/live/fabivo.com/fullchain.pem
- /docker-volumes/etc/letsencrypt/live/fabivo.com/privkey.pem:/etc/letsencrypt/live/fabivo.com/privkey.pem
ports:
- 80:80
- 443:443
links:
- laravel:laravel
- angular:angular
depends_on:
- laravel
- angular
environment:
- VIRTUAL_HOST=fabivo.com, portal.fabivo.com , api.fabivo.com, shop.fabivo.com
networks:
default:
aliases:
- api.fabivo.com
- portal.fabivo.com
- shop.fabivo.com
- fabivo.com
- api.paisaclub.com
database:
build: ./laravel/docker/mariadb
environment:
- "MYSQL_ROOT_PASSWORD=secret"
- "MYSQL_DATABASE=homestead"
- "MYSQL_USER=homestead"
- "MYSQL_PASSWORD=homestead"
ports:
- 3306:3306
volumes:
mysqldata:
networks:
default:
external:
name: nginx-proxy
nginx 配置
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name fabivo.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/fabivo.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/fabivo.com/privkey.pem;
ssl_buffer_size 8k;
ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;
location / {
# NOTE THERE IS NO TRAILING SLASH AT THE END. NO TRAILING SLASH. NO SLASH. NO!
proxy_pass http://angular:9000; # <--- THIS DOES NOT HAVE A TRAILING '/'
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name api.fabivo.com portal.fabivo.com shop.fabivo.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/fabivo.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/fabivo.com/privkey.pem;
ssl_buffer_size 8k;
ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;
location / {
try_files $uri /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass laravel:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
#CSP
# add_header Content-Security-Policy "frame-src 'self'; default-src 'self'; script-src 'self' 'unsafe-inline' https://maxcdn.bootstrapcdn.com https://ajax.googleapis.com; img-src 'self'; style-src 'self' https://maxcdn.bootstrapcdn.com; font-src 'self' data: https://maxcdn.bootstrapcdn.com; form-action 'self'; upgrade-insecure-requests;" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
}
服务器.ts
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
const domino = require('domino');
import { enableProdMode } from '@angular/core';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';
//import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();
// Express server
const app = express();
const compression = require('compression');
const PORT = process.env.PORT || 9000;
const DIST_FOLDER = join(process.cwd(), 'dist');
//
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
// Our index.html we'll use as our template
const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html'), 'utf8').toString();
const win = domino.createWindow(template);
global['window'] = win;
Object.defineProperty(win.document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true
};
},
});
global['document'] = win.document;
global['$'] = require('jquery');
global['jQuery '] = global['$'];
global['Materialize'] = win.Materialize;
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle');
const { provideModuleMap } = require('@nguniversal/module-map-ngfactory-loader');
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
app.use(compression());
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));
// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), { maxAge: '1y' }));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
res.render('index', {
req: req,
res: res
});
});
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node server listening on http://localhost:${PORT}`);
});
更新:
这是最小的复制回购 https://github.com/ssatz/Angular-SSR-HTTPS-Error Deployed to heroku HEROKU
注意:这在我的本地使用自签名证书完美运行。
解决方案
这是由于 SSL 配置。如果有人遇到问题,请将 secp384r1 更改为 prime256v1
ssl_ecdh_curve prime256v1;
推荐阅读
- python - 问:Selenium NoSuchElementException(非显式等待或 iframe)
- user-interface - 如何在 Julia、WebIO 和 Blink 中使用 handle(w, “flag”)?
- c# - C# Entity Framework LINQ to Entities 在 SELECT 表达式下添加参数 WHERE 表达式
- python - 我不明白 django 的 path() 是如何工作的
- vue.js - 如何访问 vue.js 中的索引以获取循环元素?
- unity3d - Unity 2D Top-Down 鼠标面临武器旋转问题
- android - 在没有 xml 的情况下以编程方式创建 Listview:不显示任何单元格
- python - 如何在 output.csv 文件中包含“for”循环变量
- python - 超过指定数量。的列用 Pandas 重命名
- angular - Angular:在产品模式下点击刷新后 URL 发生变化