我编写了一个 Spring Boot 后端和一个 Angular 8 前端,我将它们打包在一起。因此,在部署时,两者都使用相同的端口,并且效果很好。
在开发过程中,我希望这两个应用程序分别运行并设置如下:
应用程序.yml
server:
port: 10000
servlet:
context-path: /
DataRestController.java
@RestController
@RequestMapping("/api/data")
public class DataRestController {
@GetMapping()
public Collection<Data> findAll() {
// populate result
return result;
}
}
数据服务.ts
export class DataService {
private url = '/api/data';
constructor(private http: HttpClient) {
}
getData(): Observable<Data[]> {
return this.http.get<Data[]>(this.url);
}
}
为了让前端能够连接到后端,我在我的package.json
文件中定义了以下命令:
"start": "ng serve --proxy-config proxy.conf.json --hmr --port 4201"
proxy.conf.json
{
"/api": {
"target": "http://localhost:10000",
"secure": "false"
}
}
这一切都完美无缺。我可以将浏览器指向http://localhost:10000/api/data
并将接收 JSON 格式的数据。前端的请求http://localhost:4201/api/data
被透明地转发到后端 URL,我的 Angular 应用程序接收它的数据。
但是,现在我想切换到通过 https 进行安全通信。我采取了以下步骤:
我生成了一个带有密钥对的 PKCS12 文件,然后从中提取了私钥和证书:
keytool -genkeypair -alias data -keyalg RSA -keysize 2048 -storetype PKCS12 -validity 3650 -keystore data.p12 -storepass <password>
openssl pkcs12 -info -in data.p12 -nodes -nocerts > data.key
openssl pkcs12 -info -in data.p12 -nokeys > data.cert
我将 PKCS12 文件复制到/src/main/resources/keystore/data.p12
我的后端,将另外两个文件复制到/ssl/data.*
我的前端。
我将以下行添加到我的 * application.yml
server:
ssl:
key-store-type: pkcs12
key-store: classpath:keystore/data.p12
key-alias: data
key-store-password: ENC(<jasypt encrypted password>)
key-password: ENC(<jasypt encrypted password>)
我还添加了一个SecurityConfig.java文件
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requiresChannel()
.anyRequest()
.requiresSecure()
;
}
}
如果我现在启动我的后端应用程序,它不再响应http
URL,但它确实响应https://localhost:10000/api/data
(我第一次尝试此操作时必须告诉 firefox 接受自签名证书,但之后它可以完美运行)。
现在是我的麻烦开始的地方,当我尝试前端通过 https 与后端交谈时 :-(
我将以下脚本添加到package.json
"start-ssl": "ng serve --proxy-config proxy-secure.conf.json --hmr --port 4201 --ssl true --ssl-cert ssl/data.cert --ssl-key ssl/data.key",
并创建了一个新文件proxy-secure.conf.json
{
"/api": {
"target": "https://localhost:10000",
"secure": "true"
},
}
当我运行start-ssl
我的应用程序时https://localhost:4201
,它现在可以在浏览器中正常加载。但是,当 Angular 应用程序想要访问时,https://localhost:4201/api/data
我在控制台中收到以下错误,并且浏览器显示该请求返回了 HTTP 状态 500。
[HPM] Error occurred while trying to proxy request /api/data from localhost:4201 to localhost (DEPTH_ZERO_SELF_SIGNED_CERT) (https://nodejs.org/api/errors.html#errors_common_system_errors)
经过一番谷歌搜索后,我偶然发现了 github 上的这个对话,并按照那里给出的各种建议,我尝试了以下方法:
{
"/api": {
"target": "https://localhost:10000",
"secure": "false"
},
}
也
{
"/api": {
"target": "https://localhost:10000",
"secure": "false"
"changeOrigin": true,
},
}
我还更改了文件扩展名,所以文件现在是proxy-secure.conf.js
var fs = require('fs');
var PROXY_CONFIG = {
"/api": {
"target": {
"host": "localhost",
"port": "10000",
"protocol": "https:",
"key": fs.readFileSync('ssl/data.key'),
"cert": fs.readFileSync('ssl/data.cert')
},
"secure": "false",
"rejectUnauthorized": "false",
"changeOrigin": true,
"logLevel": "debug"
}
};
module.exports = PROXY_CONFIG;
这会在应用程序启动时产生以下输出:
[HPM] Proxy created: /api -> {
host: 'localhost',
port: '10000',
protocol: 'https:',
key: <Buffer 42 61 ... <many> more bytes>,
cert: <Buffer 42 61 ... <many> more bytes>
}
[HPM] Subscribed to http-proxy events: [ 'error', 'close' ]
但是,只要前端尝试访问后端,我仍然会收到相同的错误:
[HPM] Error occurred while trying to proxy request /api/data from localhost:4201 to localhost (DEPTH_ZERO_SELF_SIGNED_CERT) (https://nodejs.org/api/errors.html#errors_common_system_errors)
我的想法不多了,谷歌也没有帮助。我无法想象我是第一个尝试这种设置的人。反正有没有告诉角度代理不关心我的自签名证书或告诉它信任该证书?
如果我执行 ang build --prod
和 a mvn clean install
(这要归功于maven-resources-plugin
将前端的dist
文件夹复制到classes/static
char 中,然后使用java -jar data-0.0.1-SNAPSHOT.jar
一切正常运行 Spring Boot 应用程序:
我可以使用浏览器访问https://localhost:10000/api/data
并获取我的 JSON 原始数据来访问数据。我也可以去https://localhost:10000/
启动我的 Angular 应用程序,它通过 https 直接访问上面的 JSON 数据没有任何困难。
所以我的设置在生产中工作,但我无法让它在我的开发配置中使用角度代理运行。
编辑:报告有关尝试链接到的 SO 文章 Berk Kurkcuoglu 中的建议
据我所知,那篇文章描述了如何启用SSL(我对此没有任何问题),但仍然值得一试:
我已将以下内容添加到我的angular.json
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "data:build",
"hmrWarning": false,
"sslKey": "ssl/data.key",
"sslCert": "ssl/data.cert",
"ssl": true
}
},
这样做的效果是我可以在 package.json 中的条目中保留--ssl --ssl-cert <cert> --ssl-key <key>
参数ng serve
,但代理仍然会抛出相同的错误。