预检的响应在angular中没有HTTP ok状态

时间:2018-08-27 22:02:55

标签: angular http cors

我在服务中定义了以下get请求:

createAuthorizationHeader(user, pass) {
  let headers: HttpHeaders = new HttpHeaders;
  headers = headers.append('Accept', 'application/json, text/plain, */*');
  headers = headers.append('Authorization', 'Basic ' + btoa(user + ':' + pass));
  headers = headers.append('Content-Type', 'application/json; charset=utf-8');
    console.log(headers);
    return this.http.get(this._loginUrl, {
      headers: headers
    });
}

结果是:

OPTIONS https://localhost:8443/delivery/all 401 ()

Failed to load https://localhost:8443/delivery/all: Response for preflight does not have HTTP ok status.

HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: null, ok: false, …}

我也向Postman发出了相同的发帖请求,但是一切正常,因此本地服务器正常工作。

我无法弄清楚我的请求出了什么问题。

6 个答案:

答案 0 :(得分:29)

CORS合同要求在飞行前OPTIONS请求上不需要身份验证。看来您的后端需要对OPTIONS请求和GET进行身份验证。

使用Postman访问后端时,您仅发送GET。 浏览器将首先发送一个OPTIONS请求(没有您的身份验证标头),并在响应中查找“ Access-Control-Allow-Origin”标头,该标头与发出请求的页面的来源相匹配。

如果对OPTIONS响应的响应不是2xx,或者不存在标头,或者标头的值与请求页面的原点不匹配,则将得到您遇到的错误,而GET请求将不会。

TLDR;更改后端以在处理登录URL时不需要对OPTIONS方法进行身份验证。

答案 1 :(得分:6)

默认情况下,浏览器不允许用户执行跨域请求。

从Angular为避免此错误,我们可以使用代理配置。

假设angular ui在本地主机:4200上工作,并且它想调用其余的终点网址,例如:https://localhost:8443/delivery/all

以下步骤将解决此问题。

  1. 在您的角度应用程序根文件夹中创建一个proxy.config.json文件。 (哪里存在package.json文件) 代理所做的只是简单地在您的前端应用程序运行所在的域+端口上获取浏览器请求,然后将该请求转发到您的后端API服务器。 CORS是浏览器的安全性问题,不适用于进行“后端到后端”通信时(如中间使用代理的情况)。

    内容应如下所示。

    示例:

    {
        "/delivery/all/*": {
        "target": "https://localhost:8443",
        "secure": false,
        "logLevel": "debug",
        "changeOrigin": true
        }
    }
    

    在我们的应用程序中对/ delivery / all / ...的所有请求都将转发到https://localhost:8443/delivery/all/

    注意:changeOrigin属性。当您在后端使用某些虚拟代理(例如使用Apache2配置的代理)时,绝对必须将其设置为true

  2. 在运行应用程序时添加代理配置。 Angular支持“ --proxy-config”,您可以在其中提供代理配置文件。 如果使用“ npm start”选项进行测试,则必须添加“ --proxy-config”选项,如下所示。它必须添加到package.json文件中。

     "scripts": {
    
    "ng": "ng",
    "start": "ng serve --proxy-config proxy.config.json",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
    }
    

    如果直接使用“ ng serve”运行,则已对其进行了如下修改。     “ ng serve --proxy-config proxy.config.json”

  3. 可以将Angular应用程序中的HTTP调用更改为此。服务器将自动将请求转发到“ https://localhost:8443/delivery/all”。

    this.http.get('https://localhost:8443/delivery/all')             .map(res => res.json());

    this.http.get('/ delivery / all')         .map(res => res.json());

这里是更多信息的链接:https://sudhasoftjava.wordpress.com/2018/10/05/proxy-configuration-in-angular/

答案 2 :(得分:0)

@Daryl

我们要做的是为Cors添加自定义配置。然后通过Java服务器中的安全配置启用它。如答案中所述,仅对该服务器启用了直接REST调用。

@Configuration
public class CorsConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
                        .allowedHeaders("*");
            }
        };
    }
}

这进入了网络安全配置:

@Override
    protected void configure(final HttpSecurity http) throws Exception {
        http.csrf().disable()
                .antMatcher("/**")
                .authorizeRequests().and()
                .httpBasic()
                .and()
                .authorizeRequests().anyRequest().authenticated().and().cors();
    }

答案 3 :(得分:0)

如果是.Net Web API项目,请编辑web.config并删除下面的标记。

<handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

答案 4 :(得分:0)

将此行添加到服务器标头配置的末尾

status_header(200);

应该解决问题

答案 5 :(得分:0)

在POST请求之前反应应用程序发送POST请求以检查您的API。
您需要在nginx.conf中添加此代码段。

location /api/ {
    if ($request_method = 'OPTIONS') {
        return 204;
    }
    proxy_pass http://localhost:8080;
}