由于 CORS 导致 HTTP 发布请求失败

Posted

技术标签:

【中文标题】由于 CORS 导致 HTTP 发布请求失败【英文标题】:Failed HTTP post request because of CORS 【发布时间】:2016-06-18 21:51:17 【问题描述】:

我无法让我的应用程序运行。我整天都在读这个,尝试了很多东西,但最后没有任何效果。在最后一次尝试中,我尝试了这个link。我有 java 后端作为 RESTful Web 服务,没有任何额外的框架,如 Jersey 或 RESTeasy,只是纯 java。我有我的登录 POST 方法:

@POST
@Path("login")
@Produces(value = "application/json")
public Response login() 

    AccountAuthentificator authentificator = AccountAuthentificator.getInstance();
    Status status = Response.Status.OK;

    String credentialValue = getHeaderValue(AccountAuthentificator.AUTH_CREDENTIALS);
    if (credentialValue == null) 
        status = Response.Status.FORBIDDEN;
        return WebServiceUtil.createResponse(status, "Missing account credentials in header.");
    

    try 
        LoginResponse res = authentificator.login(credentialValue);
        return WebServiceUtil.createResponse(status, res);
     catch (AccessControlException e) 
        status = Response.Status.FORBIDDEN;
        return WebServiceUtil.createResponse(status,
                "User does not exist. Please verify your user name and password.");
    

WebServiceUtil.createResponse 方法基本上添加了必要的标头,如您在此处看到的:

public static Response createResponse(Status status, Object responseContent) 

    ResponseBuilder resBuilder = Response.status(status.getStatusCode());

    resBuilder.header("Access-Control-Allow-Origin", "*");
    resBuilder.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
    resBuilder.header("Access-Control-Allow-Credentials", "true");
    resBuilder.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");

    resBuilder.allow("OPTIONS");

    resBuilder.entity(getJSONAsString(responseContent));

    return resBuilder.build();

我还看到人们使用了另一种方法。它带有过滤器,例如example。我还想知道我的实现是否与此不同以及预检定义的确切位置 - 在我的实现中是 .allow("OPTIONS") 执行此操作,但您可以纠正我的错误。

然后我有我的 Web 应用程序,我在其中调用此 POST 方法。我为此使用AngularJS。在我的 AuthenticateController 控制器中,我有 Login 方法,在登录表单中提交时调用该方法。实现如下所示:

function Login(username, password) 
        // CreateLoginHeader creates the authorization token through the login values username and password
        var authdata = CreateLoginHeader(username, password);
        var config = 
                withCredentials: true,
                headers:   'Authorization': authdata 
        ;
        $http.post('http://XXXX', config).then(SuccessLogin, ErrorLogin);
    

有人知道这里出了什么问题吗?通过 chrome 开发人员工具,我可以看到错误“XMLHttpRequest 无法加载'placeholder-server-URL'。对预检请求的响应未通过访问控制检查:没有'Access-Control-Allow-Origin'标头存在于请求的资源。因此,不允许访问源“占位符-客户端-URL”。”。

在调用后端时,我是否应该在客户端添加这两个标头值:

访问控制请求方法 访问控制请求标头

【问题讨论】:

那你为什么要进行跨域调用呢? CORS 标头与客户端无关,服务器需要添加它们。 '没有任何额外框架(如 Jersey 或 RESTeasy)的 RESTful Web 服务' - 你确定吗?见:***.com/tags/jax-rs/info 对不起,你是对的,我使用 javax: javaxjavaee-api7​​.0在我的 maven pom.xml 文件中提供了。是的,我还从我所读到的内容中认为,CORS 标头必须仅在服务器端 @epascarello 上实现。碰巧我遵循了另一个示例并以编程方式添加了这些值。但据我所知,它们应该已经通过浏览器创建了。 【参考方案1】:

login 不处理 Options 请求,因此不调用 createResponse

看看:https://blogs.oracle.com/theaquarium/entry/supporting_cors_in_jax_rs(你应该实现一个javax.ws.rs.container.ContainerResponseFilter,见How to handle CORS using JAX-RS with Jersey)

您的代码在这里的另一种可能性(但如果您开发一个“真正的”应用程序则不是):将@javax.ws.rs.OPTIONS 添加到您的方法中,就像您对@javax.ws.rs.POST 所做的那样。

【讨论】:

好的,我尝试过这种方式,并且坚持使用教程here。我唯一没有做的就是像他一样更改 web.xml 文件。我正在扩展 Application 类并在其中添加我的类以及所有已定义的 post/get 方法。我还将记录器用于过滤器,似乎没有在请求和响应上调用过滤器。知道为什么会这样吗? 基本上这是我的应用程序类:@ApplicationPath("/api/v1/brain") public class ApplicationConfig extends Application public Set<Class<?>> getClasses() Set<Class<?>> s = new HashSet<Class<?>>(); s.add(StudyManagerService.class); return s; 尝试像 StudyManagerService 一样注册过滤器(“提供者”)。 这一改变起到了作用。我添加了我的两个过滤器类:s.add(StudyManagerService.class); s.add(RESTRequestFilter.class); s.add(RESTResponseFilter.class); 现在似乎我在前端有一个例外,但至少我更进一步。谢谢@meiko 不客气,也许您可​​以将答案标记为正确;)

以上是关于由于 CORS 导致 HTTP 发布请求失败的主要内容,如果未能解决你的问题,请参考以下文章

每当 CORS $http 请求失败时,返回的响应始终为 0

2021-09-13 一文解析前端请求307导致CORS跨域失败

为啥我的 CORS 请求因 http 401 错误而失败

由于CORS政策,谷歌oAuth的角度请求失败

AngularJS $http 从失败的 CORS 请求返回状态码 0

Angular 跨域请求 CORS 失败,但节点 http.get() 成功返回