从AngularJS启用CORS Post请求到Jersey

时间:2022-08-22 17:46:21

I'm attempting to post a JSON document from an AngularJS app to a Jersey REST service. The request fails, informing me that:

我正在尝试将JSON文档从AngularJS应用程序发布到Jersey REST服务。请求失败,通知我:

XMLHttpRequest cannot load http://localhost:8080/my.rest.service/api/order/addOrder. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.

XMLHttpRequest无法加载http://localhost:8080 / my.rest.service / api /订单/ addOrder。在请求的资源上不存在“访问控制允许起源”的标头。因此,不允许访问起源'http://localhost'。

Jersey REST Post Function

I have enabled (what I believe to be) the appropriate headers: Access-Control-Allow-Origin and Access-Control-Allow-Methods on the response, as seen in the method below:

我在响应上启用了(我认为是)适当的header: Access-Control-Allow-Origin和Access-Control-Allow-Methods,如下面的方法所示:

@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/addOrder")
public Response addOrder(DBObject dbobject) {
    DB db = mongo.getDB("staffing");
    DBCollection col = db.getCollection("orders");
    col.insert(dbobject);
    ObjectId id = (ObjectId)dbobject.get("_id");
    return Response.ok()
            .entity(id)
            .header("Access-Control-Allow-Origin","*")
            .header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
            .allow("OPTIONS")
            .build();
}

Angular JS Controller

I've declared the app and configured the $httpProvider with all of the settings suggested in similar Stack Overflow questions:

我已经声明了应用程序,并配置了$httpProvider与类似的栈溢出问题中建议的所有设置:

var staffingApp = angular.module('myApp', ['ngRoute', 'ui.bootstrap']);
myApp.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.defaults.useXDomain = true;
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
    $httpProvider.defaults.headers.common["Accept"] = "application/json";
    $httpProvider.defaults.headers.common["Content-Type"] = "application/json";
 }]);

I've also created this controller to open a modal and handle the form:

我还创建了这个控制器来打开一个模态并处理表单:

    var modalCtrl = function($scope, $modal, $log, $http, $location) {          
    $scope.order = {
        activityTitle : null,
        anticipatedAwardDate : null,
        component : null,
        activityGroup : null,
        activityCategory : null,
        activityDescription : null
    };
    $scope.open = function () {
        var modalInstance = $modal.open({
            templateUrl: 'addOrder.html',
            windowClass: 'modal',
            controller: modalInstanceCtrl,
            resolve: {
                order : function () {
                    return $scope.order;
                    }
                }
            });
        modalInstance.result.then(function (oid) {
            $log.info("Form Submitted, headed to page...");
            $location.path("/orders/" + oid);
        }, function() { 
            $log.info("Form Cancelled")
        });
    };
};

var modalInstanceCtrl = function ($scope, $modalInstance, $log, $http, order) {
    $scope.order = order,
    $scope.ok = function () {
        $log.log('Submitting user info');
        $log.log(order);
        $log.log('And now in JSON....');
        $log.log(JSON.stringify(order));
        $http.post('http://localhost:8080/my.rest.service/api/order/addOrder', JSON.stringify(order)).success(function(data){
            $log.log("here's the data:\n");
            $log.log(data);
            $modalInstance.close(data._id.$oid)
        });
    };
    $scope.cancel = function () {
        $modalInstance.dismiss('cancel');
    };      
};
myApp.controller('modalCtrl', modalCtrl);

To no avail, I've tried:

我试过:

  • removing .allow("OPTIONS") from the response headers.
  • 从响应头中删除.allow(“选项”)。
  • removing the $httpProvider configuration from the application
  • 从应用程序中删除$httpProvider配置
  • changed the $httpProvider configuration to call myApp.config(function ($httpProvider) {...}), passing the function itself rather than the array.
  • 将$httpProvider配置改为调用myApp。配置(函数($httpProvider){…}),传递函数本身而不是数组。

Get requests work with the same configuration:

让请求与相同的配置一起工作:

@GET
@Path("/listall/")
@Produces(MediaType.APPLICATION_JSON)
public Response listAll(){
    DB db = mongo.getDB("staffing");
    DBCollection col = db.getCollection("orders");
    List<DBObject> res = col.find().limit(200).toArray();
    return Response.ok()
            .entity(res.toString())
            .header("Access-Control-Allow-Origin","*")
            .header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
            .allow("OPTIONS")
            .build();       
}

with this controller that works fine:

有了这个控制器就可以了:

myApp.controller('orderListCtrl', function ($scope, $http){
    $http.get('http://localhost:8080/my.rest.service/api/order/listall').success(function(data) {
        for (var i = 0; i < data.length; i++) {
            if (data[i].description.length > 200) {
                data[i].shortDesc = data[i].description.substring(0,196) + "...";
            } else {
                data[i].shortDesc = data[i].description;
            }
        };
        $scope.orders = data;
    });
});

Update #1:

I've tried the same request on a same origin basis, essentially serving the Angular application alongside the REST service from locahost:8080. This configuration worked, but required a slight change and some general clean up in my code, which I've edited above.

我在相同的原点基础上尝试了相同的请求,从locahost:8080中提供了与REST服务一起使用的角度应用程序。这个配置是有效的,但是需要在我的代码中做一些轻微的更改和一些一般性的清理,我在上面对代码进行了编辑。

The Post still fails as a CORS request, however so I'm still looking for the missing piece in this configuration.

但是,这个帖子仍然不能作为CORS的请求,所以我仍然在寻找这个配置中缺失的部分。

Update #2:

I've investigated the headers of the working request as they're delivered to the browser and compared them with the non-working request.

我已经研究了工作请求的报头,当它们被发送到浏览器时,并将它们与非工作请求进行了比较。

The working get request returns the following headers with its response: 从AngularJS启用CORS Post请求到Jersey

工作get请求将返回以下标题,其响应如下:

The non-working post request returns headers with its response, but is missing the Access-Control-Allow-Origin header:

非工作的post请求返回其响应的标头,但缺少访问控制允许的标头:

从AngularJS启用CORS Post请求到Jersey

I believe this has now become an issue of the headers being stripped off of the response prior to returning it to the client, which would then cause the browser to fail the request.

我认为这现在已经成为一个问题,即在将响应返回给客户端之前,会将报头从响应中删除,从而导致浏览器失败请求。

Update #3:

Submitting a test POST request to the same URL from Chrome's REST Console extension returns the appropriate response headers, as seen in the screencap below. 从AngularJS启用CORS Post请求到Jersey

从Chrome的REST控制台扩展向同一个URL提交测试POST请求将返回适当的响应头,如下面的screencap所示。

At this point, I can't determine what's removing the headers between Jersey and my Angular client, but I'm fairly confident that's the culprit.

在这一点上,我不能确定是什么原因使泽西和我的客户之间的头,但我相信这是罪魁祸首。

4 个解决方案

#1


8  

The problem turned out to be inadequate handling of the OPTIONS request sent in pre-flight prior to the POST request with the proper cross origin headers.

问题是处理在起飞前发送的选项请求时处理不当,而在发送后请求之前使用正确的交叉源头。

I was able to resolve the issue by downloading and implementing the CORS filter found at this page: http://software.dzhuvinov.com/cors-filter-installation.html.

我可以通过下载并实现这个页面上找到的CORS过滤器来解决这个问题:http://software.dzhuvinov.com/cors-filter- install.html。

If you're experiencing a similar problem, follow the instructions and test to see that your OPTIONS request is no longer failing, and is immediately followed by your successful request.

如果您遇到类似的问题,请按照说明和测试,以确保您的选项请求不再失败,并立即执行成功的请求。

#2


2  

Best way is to add Jersey Response filter which will add the CORS headers for all the methods. You don't have to change your webservices implementation.

最好的方法是添加Jersey Response过滤器,它将为所有方法添加CORS header。您不必更改webservices实现。

I will explain for Jersey 2.x

我会为新泽西2。x解释

1) First add a ResponseFilter as shown below

1)首先添加一个ResponseFilter,如下所示

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;

public class CorsResponseFilter implements ContainerResponseFilter {

@Override
public void filter(ContainerRequestContext requestContext,   ContainerResponseContext responseContext)
    throws IOException {
        responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
        responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");

  }
}

2) then in the web.xml , in the jersey servlet declaration add the below

2)然后在网络上。在jersey servlet声明中添加下面的xml

    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>YOUR PACKAGE.CorsResponseFilter</param-value>
    </init-param>

#3


0  

I had faced similar CORS error while calling my Restful service (implemented in java - Jersey) from angularjs. To fix it I added Access-Control-Allow-Origin: * in response header. I added below :

在从angularjs调用Restful服务(在java - Jersey中实现)时,我遇到了类似的CORS错误。为了修复它,我在响应头中添加了Access-Control-Allow-Origin: *。我添加了以下:

response.addHeader("Access-Control-Allow-Origin", "*"); 

For more information you can check - http://enable-cors.org/server.html

有关更多信息,请查看http://enable-cors.org/server.html

CORS error occurs typically when your angularjs code (web project) and webserivce code (server side project) are on different IP and port no.

当您的angularjs代码(web项目)和webserivce代码(服务器端项目)位于不同的IP和端口号上时,通常会发生CORS错误。

Your webservice implementation looks correct. So just to check, try running them on localhost on same port (eg. 8080). It should work there if all code is correct.

您的webservice实现看起来是正确的。因此,为了检查,请尝试在相同端口上的localhost上运行它们(例如。8080)。如果所有代码都是正确的,那么它应该可以在那里工作。

In order to run them separately try adding Access-Control-Allow-Origin: * in webservice implementation as shown above.

为了单独运行它们,请尝试在webservice实现中添加访问控制允许的来源:*,如上所示。

Hope this helps.

希望这个有帮助。

#4


0  

Actually, you have other solution that does not need a filter. Adding the Access-Control-Allow-* headers to the GET request, is not enough, you have to create an OPTIONS endpoint to allow browsers do the pre-flight request, i.e.:

实际上,您还有其他不需要过滤器的解决方案。在GET请求中添加Access-Control-Allow-* header是不够的,您必须创建一个选项端点来允许浏览器执行飞行前请求,例如:

@OPTIONS
public Response corsMyResource(@HeaderParam("Access-Control-Request-Headers") String requestH) {
    ResponseBuilder rb = Response.ok();

    return buildResponse(rb, requestH);
}

see https://kdecherf.com/blog/2011/06/19/java-jersey-a-cors-compliant-rest-api/ for reference.

看到https://kdecherf.com/blog/2011/06/19/java-jersey-a-cors-compliant-rest-api/供参考。

#1


8  

The problem turned out to be inadequate handling of the OPTIONS request sent in pre-flight prior to the POST request with the proper cross origin headers.

问题是处理在起飞前发送的选项请求时处理不当,而在发送后请求之前使用正确的交叉源头。

I was able to resolve the issue by downloading and implementing the CORS filter found at this page: http://software.dzhuvinov.com/cors-filter-installation.html.

我可以通过下载并实现这个页面上找到的CORS过滤器来解决这个问题:http://software.dzhuvinov.com/cors-filter- install.html。

If you're experiencing a similar problem, follow the instructions and test to see that your OPTIONS request is no longer failing, and is immediately followed by your successful request.

如果您遇到类似的问题,请按照说明和测试,以确保您的选项请求不再失败,并立即执行成功的请求。

#2


2  

Best way is to add Jersey Response filter which will add the CORS headers for all the methods. You don't have to change your webservices implementation.

最好的方法是添加Jersey Response过滤器,它将为所有方法添加CORS header。您不必更改webservices实现。

I will explain for Jersey 2.x

我会为新泽西2。x解释

1) First add a ResponseFilter as shown below

1)首先添加一个ResponseFilter,如下所示

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;

public class CorsResponseFilter implements ContainerResponseFilter {

@Override
public void filter(ContainerRequestContext requestContext,   ContainerResponseContext responseContext)
    throws IOException {
        responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
        responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");

  }
}

2) then in the web.xml , in the jersey servlet declaration add the below

2)然后在网络上。在jersey servlet声明中添加下面的xml

    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>YOUR PACKAGE.CorsResponseFilter</param-value>
    </init-param>

#3


0  

I had faced similar CORS error while calling my Restful service (implemented in java - Jersey) from angularjs. To fix it I added Access-Control-Allow-Origin: * in response header. I added below :

在从angularjs调用Restful服务(在java - Jersey中实现)时,我遇到了类似的CORS错误。为了修复它,我在响应头中添加了Access-Control-Allow-Origin: *。我添加了以下:

response.addHeader("Access-Control-Allow-Origin", "*"); 

For more information you can check - http://enable-cors.org/server.html

有关更多信息,请查看http://enable-cors.org/server.html

CORS error occurs typically when your angularjs code (web project) and webserivce code (server side project) are on different IP and port no.

当您的angularjs代码(web项目)和webserivce代码(服务器端项目)位于不同的IP和端口号上时,通常会发生CORS错误。

Your webservice implementation looks correct. So just to check, try running them on localhost on same port (eg. 8080). It should work there if all code is correct.

您的webservice实现看起来是正确的。因此,为了检查,请尝试在相同端口上的localhost上运行它们(例如。8080)。如果所有代码都是正确的,那么它应该可以在那里工作。

In order to run them separately try adding Access-Control-Allow-Origin: * in webservice implementation as shown above.

为了单独运行它们,请尝试在webservice实现中添加访问控制允许的来源:*,如上所示。

Hope this helps.

希望这个有帮助。

#4


0  

Actually, you have other solution that does not need a filter. Adding the Access-Control-Allow-* headers to the GET request, is not enough, you have to create an OPTIONS endpoint to allow browsers do the pre-flight request, i.e.:

实际上,您还有其他不需要过滤器的解决方案。在GET请求中添加Access-Control-Allow-* header是不够的,您必须创建一个选项端点来允许浏览器执行飞行前请求,例如:

@OPTIONS
public Response corsMyResource(@HeaderParam("Access-Control-Request-Headers") String requestH) {
    ResponseBuilder rb = Response.ok();

    return buildResponse(rb, requestH);
}

see https://kdecherf.com/blog/2011/06/19/java-jersey-a-cors-compliant-rest-api/ for reference.

看到https://kdecherf.com/blog/2011/06/19/java-jersey-a-cors-compliant-rest-api/供参考。