1

我编写了一个 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()
    ;
  }
}

如果我现在启动我的后端应用程序,它不再响应httpURL,但它确实响应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/staticchar 中,然后使用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,但代理仍然会抛出相同的错误。

4

1 回答 1

0

嗯,这很尴尬。

事实证明,正确的答案一直都在那里(在SOGithub上),而我只是愚蠢地看到它。

我的proxy.conf.json文件如下所示:

{
  "/api": {
    "target": "https://localhost:10000",
    "secure": "false"
  },
}

什么时候应该是:

{
  "/api": {
    "target": "https://localhost:10000",
    "secure": false
  },
}

(注意布尔值而不是字符串。当然两者"true"都是"false"真实的,所以两者都true在我的配置中。

现在我已将其更改为false,一切正常。

于 2020-12-05T12:45:01.140 回答