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 无关,这是您的浏览器造成的。
我假设您的服务器运行在 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)。
使用angular cli 配置
https://angular.io/guide/build#proxying-to-a-backend-server
使用 NestJS/Express 后端,我通过启用 CORS 解决了这个问题:https://docs.nestjs.com/techniques/security#cors
我是使用 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 无关,这是您的浏览器造成的。
我假设您的服务器运行在 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)。
使用angular cli 配置 https://angular.io/guide/build#proxying-to-a-backend-server
使用 NestJS/Express 后端,我通过启用 CORS 解决了这个问题:https://docs.nestjs.com/techniques/security#cors