[英]Enable CORS Post Request from AngularJS to Jersey
我正在尝试将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.
我已启用(相信是这样)适当的标头:响应中的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();
}
我已经声明了应用程序,并为$ httpProvider配置了类似Stack Overflow问题中建议的所有设置:
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";
}]);
我还创建了此控制器来打开模式并处理表单:
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);
无济于事,我试过了:
.allow("OPTIONS")
。 获取请求使用相同的配置:
@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();
}
使用此控制器可以正常工作:
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;
});
});
我已经在相同的来源基础上尝试了相同的请求,实际上是与locahost:8080的REST服务一起为Angular应用程序提供服务。 此配置有效,但需要稍作更改,并在上面编辑过的代码中进行了一些常规整理。
由于CORS请求,该帖子仍然失败,但是,我仍然在此配置中寻找丢失的部分。
在将工作请求的标头传递到浏览器时,我已经对其进行了调查,并将其与不工作的请求进行了比较。
工作的get请求返回以下标头及其响应:
无效的发布请求返回标头及其响应,但缺少Access-Control-Allow-Origin标头:
我认为,这已经成为一个问题,即在将响应返回给客户端之前,已从响应中剥离了标头,这将导致浏览器使请求失败。
从Chrome的REST Console扩展程序向相同的URL提交测试POST请求,将返回相应的响应标头,如下面的屏幕截图所示。
在这一点上,我无法确定是什么删除了Jersey和我的Angular客户端之间的标头,但是我很确定这是罪魁祸首。
事实证明,此问题是在处理POST请求之前使用正确的跨源标头对在飞行前发送的OPTIONS请求的处理不充分。
通过下载并实现在此页面上找到的CORS过滤器,我能够解决此问题: http : //software.dzhuvinov.com/cors-filter-installation.html 。
如果您遇到类似的问题,请按照说明进行测试,以确保您的OPTIONS请求不再失败,并且紧随其后的是成功的请求。
最好的方法是添加Jersey响应过滤器,该过滤器将为所有方法添加CORS标头。 您不必更改Web服务的实现。
我将为Jersey 2.x进行解释
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)然后在web.xml的jersey servlet声明中添加以下内容
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>YOUR PACKAGE.CorsResponseFilter</param-value>
</init-param>
从angularjs调用Restful服务(在Java-Jersey中实现)时,我遇到了类似的CORS错误。 为了解决这个问题,我在响应头中添加了Access-Control-Allow-Origin:* 。 我在下面添加:
response.addHeader("Access-Control-Allow-Origin", "*");
有关更多信息,您可以查看-http://enable-cors.org/server.html
当您的angularjs代码(网络项目)和webserivce代码(服务器端项目)位于不同的IP和端口号时,通常会发生CORS错误。
您的Web服务实现看起来正确。 因此,仅检查一下,尝试在同一端口(例如8080)的localhost上运行它们。 如果所有代码正确,它应该在那里工作。
为了分别运行它们,请尝试在网络服务实现中添加Access-Control-Allow-Origin:* ,如上所示。
希望这可以帮助。
实际上,您还有其他不需要过滤器的解决方案。 仅向GET
请求中添加Access-Control-Allow-*
标头是不够的,您必须创建一个OPTIONS
端点以允许浏览器执行飞行前请求,即:
@OPTIONS
public Response corsMyResource(@HeaderParam("Access-Control-Request-Headers") String requestH) {
ResponseBuilder rb = Response.ok();
return buildResponse(rb, requestH);
}
请参阅https://kdecherf.com/blog/2011/06/19/java-jersey-a-cors-compatible-rest-api/以获取参考。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.