来自 jQuery 的 CORS 成功但使用 AngularJs 失败

Posted

技术标签:

【中文标题】来自 jQuery 的 CORS 成功但使用 AngularJs 失败【英文标题】:CORS From jQuery Succeeds But Fails With AngularJs 【发布时间】:2016-07-15 08:58:59 【问题描述】:

我的 Java Spring API 启用了 CORS,我想使用 AngularJS 对其进行调用。我首先编写了一个演示 jQuery 代码来测试 CORS,它运行良好。然后我写了一个等效的 AngularJS 代码,它总是产生相同的错误 -

XMLHttpRequest cannot load http://localhost:8080/my_project_name/api/get_some_data. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 401.

在研究从 AngularJS 发出 CORS 请求时,大多数结果都表明 AngularJS 在发出 CORS 请求时不需要进行任何更改,但它似乎不起作用。有什么我做错或遗漏的吗?顺便说一句,我正在使用 AngularJS v1.3.15。

以下是我在 Spring 应用程序中启用 CORS 的方式 (BaseWebConfig 扩展 WebMvcConfigurerAdapter) -

public class WebConfig extends BaseWebConfig 

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) 
        super.configureMessageConverters(converters);
        ResourceHttpMessageConverter resourceHttpMessageConverter = new ResourceHttpMessageConverter();
        converters.add(resourceHttpMessageConverter);
    

    @Override
    public void addCorsMappings(CorsRegistry registry) 
        // allow cross-origin API requests
        registry
                .addMapping("/api/**")
                .allowedMethods(
                        HttpMethod.GET.name(),
                        HttpMethod.HEAD.name(),
                        HttpMethod.POST.name(),
                        HttpMethod.PUT.name(),
                        HttpMethod.OPTIONS.name())
                .allowCredentials(false);
    


我首先使用如下的 jQuery 代码测试 CORS,它运行良好 -

$(function() 
                $('#submit_jquery').click(function() 
                    var token = $('#token').val().trim();
                    var headerValue = "Bearer " + token;
                    var body = $('#body').val().trim();
                    var domain = $('#api_domain').val().trim();
                    $('#result').text('');
                    $.ajax(
                        method : 'POST',
                        url : domain + '/api/get_some_data',
                        contentType : 'application/json',
                        data : body,
                        beforeSend : function(xhr) 
                            xhr.setRequestHeader("Authorization", headerValue);
                        ,
                        success : function(json) 
                            console.log('success');
                            $('#result').html('<pre>' + JSON.stringify(json, undefined, 2) + '</pre>');
                        ,
                        error : function(xhr, textStatus, errorThrown) 
                            console.log('error');
                        ,
                        complete : function() 
                            console.log('complete');
                        
                    );
                    return false;
                );
            );

然后我写了一个等效的AngularJS代码如下-

app.controller('CorsController', ['$scope', '$http',
                function($scope, $http) 
                    $scope.makeCorsRequest = function() 
                        var token = $('#token').val().trim();
                        var headerValue = "Bearer " + token;
                        var body = $('#body').val().trim();
                        var domain = $('#api_domain').val().trim();
                        var url = domain + '/api/get_some_data';
                        var header = 'Authorization': headerValue, 'Content-Type': 'application/json';

                        $http(
                            method: 'POST',
                            url: url,
                            header: header,
                            data: body
                        ).then(
                                //success callback
                                function (data) 
                                    console.log('SUCCESS');
                                    console.log(data);
                                ,
                                //error callback
                                function (errorMessage) 
                                    console.error('ERROR');
                                    console.error(errorMessage);
                                
                        );
                    ;
                ]);

从 jQuery 调用时的 API 响应头如下。浏览器实际上进行了两次调用-

第一个响应的标题 -

Access-Control-Allow-Headers:accept, authorization, content-type
Access-Control-Allow-Methods:GET,HEAD,POST,PUT,OPTIONS
Access-Control-Allow-Origin:*
Access-Control-Max-Age:1800
Allow:GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length:0
Date:Mon, 28 Mar 2016 10:30:00 GMT
Server:Apache-Coyote/1.1
Vary:Origin

第二个响应的标题 -

Access-Control-Allow-Origin:*
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Type:application/json
Date:Mon, 28 Mar 2016 10:30:00 GMT
Expires:0
Pragma:no-cache
Server:Apache-Coyote/1.1
Transfer-Encoding:chunked
Vary:Origin
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

【问题讨论】:

【参考方案1】:

您尚未启用 CORS。 Access-Control-Allow-Origin 标头需要在标头中设置为 * 用于 CORS。

尝试使用.allowedOrigins("http://localhost:8000"); 或更好地使用.allowedOrigins("*");。 你可以在https://spring.io/guides/gs/rest-service-cors/阅读这篇文章

来自401,我认为身份验证存在一些错误。使用headers 而不是header,如下所示,并检查是否可行。

$http(
    method: 'POST',
    url: url,
    headers: header, //use headers here
    data: body
)

【讨论】:

你能在这种情况下显示 API 响应标头吗?您可以为此使用 chrome 调试器工具。 我已经用所需的详细信息更新了问题。 标题现在很好。您是否将 401 作为 HTTP 状态代码? 从 jQuery 请求中,两个调用都有 200 状态。来自 Angular,是的,我得到 401。 401 表示身份验证错误。检查更新的答案。

以上是关于来自 jQuery 的 CORS 成功但使用 AngularJs 失败的主要内容,如果未能解决你的问题,请参考以下文章

CouchdB Jquery Ajax POST CORS

带有 Node.js 和 jQuery 的 CORS

尽管有 web.config 条目,但带有 ASP.NET WCF 服务的 jQuery AJAX CORS 无法正常工作

Vue/Axios CORS 成功但响应为空

配置 CORS 网页后返回错误但也有结果

如何使用 Web 服务和 jQuery Ajax 启用 CORS