Angular HttpClient 不发送 POST,它发送选项

Angular HttpClient doesn't send POST, it sends OPTIONS

我是使用 Angular HttpClient 的新手(也会写英文)

我有问题,我正在尝试使用 POST 方法发送 HTTP 请求以协商 OAuth 令牌阻塞,但 angular 发送 OPTIONS 请求:

服务:

login(username: string, password: string) {
const body = `username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}&grant_type=password`;

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': 'Basic ' + btoa(TOKEN_AUTH_USERNAME + ':' + TOKEN_AUTH_PASSWORD)
  })
};  


return this.http.post<string>(AuthenticationService.AUTH_TOKEN, body, httpOptions);

结果:

对于我的后端,我正在使用 Spring 安全性并且我添加了一个过滤器以允许 CORS:

@Bean
public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(0);
    return bean;
}

OPTIONS 请求首先发送,因为 CORS,Angular 需要您后端的许可才能知道它是否可以 POST。因此,在您的后端,您需要启用 CORS 才能使 http 请求正常运行。

这与 angular 无关,这是您的浏览器造成的。

Check this issue.

我假设您的服务器运行在 localhost:8080,您的 angular 应用程序运行在 localhost:4200。因为,你的请求是一个跨源请求,浏览器首先发送一个 OPTIONS 请求来查看它是否安全。此时,您的服务器 returns 一个带有 http 代码 401 的响应阻止了 post 请求。 要么你必须在你的服务器上做一些配置,要么你可以使用 webpack 代理。这仅适用于您的本地计算机。如果您从服务器提供捆绑的 angular 应用程序,那么您无需为生产做任何事情。我已经使用这种技术很长一段时间了,而且效果很好。

示例,

用户从我的域访问我的 angular 应用程序。com/ng-app 我还从同一个域 mydomain 服务 api。com/api

所以我的应用程序总是向正在为其提供服务的服务器发出请求,这不会导致生产出现问题。

对于后者,您可以执行以下操作

在项目的根目录下创建一个 proxy.conf.json(在 package.json 旁边) 并将以下内容放入

{
    "/api/": {
        "target": "http://localhost:8080",
        "secure": false,
        "changeOrigin": true
    }
}

在 package.json 中,编辑您的 start 脚本并将其设为 ng serve --proxy-config proxy.conf.json

此外,从您的前端,不要直接将请求发送到 localhost:8080,而只需编写类似 http.post('/api/getSomeData') 的内容,这将向 localhost:4200 发出请求,然后将其重定向到localhost:8080。这样,您就不必处理 CORS。

终于找到错误了。 过滤器的顺序不正确。我将它调整为 Ordered.HIGHEST_PRECEDENCE 这样它会覆盖 Spring 过滤器。

@Bean
public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
}

对于 spring 启动应用程序,要启用 cors 请求,请在您各自的控制器上使用 @CrossOrigin(origins = "*", maxAge = 3600)。

Refer this

使用angular cli 配置 https://angular.io/guide/build#proxying-to-a-backend-server

使用 NestJS/Express 后端,我通过启用 CORS 解决了这个问题:https://docs.nestjs.com/techniques/security#cors