我有一个骨干客户端应用程序和spring restful服务器。客户端应用程序位于localhost上,服务器端应用程序位于localhost:8080上。如果我将我的模型URL设置为localhost,它将运行POST(显然失败)。如果我将url设置为正确的localhost:8080,则会运行OPTIONS。
我已经实现了一个OPTIONS控制器,它可以回应请求。我可以看到API在chrome的开发工具和wfetch中正确回答。
但POST永远不会运行。
这是客户端代码:
var cfd = function () {
var config = {
serverURL: 'http://localhost:8080'
};
function init(authString) {
var authHash = window.btoa(authString);
$.ajaxSetup({
headers: {
Authorization: 'Basic ' + authHash
}
});
}
var RegistrationModel = Backbone.Model.extend({
url: config.serverURL,
defaults: {
regFname: '',
regLname: '',
regHeardHow: 0
}
});
var AuthModel = Backbone.Model.extend({
url: config.serverURL,
defaults: {
action: ''
}
});
var UserModel = Backbone.Model.extend({
url: config.serverURL + '/user',
defaults: {
email: '',
fName: '',
lName: '',
heardHow: 0,
isDeleted: 0
}
});
return {
AuthModel: AuthModel,
RegistrationModel: RegistrationModel,
UserModel: UserModel,
config: config,
init: init
};
}();
而且......
var model;
cfd.init($('#email').val() + ':');
model = new cfd.UserModel({
email: 'test@example.com',
fName: 'Test',
lName: 'Dude',
heardHow: 21,
isDeleted: 0
});
model.save();
这是我的API响应OPTIONS:
RESPONSE: **************\nHTTP/1.1 200 OK\r\n
Server: Apache-Coyote/1.1\r\n
Allow: POST,PUT,GET,DELETE,OPTIONS\r\n
Content-Length: 0\r\n
Date: Mon, 06 Jan 2014 16:30:31 GMT\r\n
\r\n
我已尝试使用响应代码200和204.
为了完整性,这是我的OPTIONS控制器:
@Controller
public class OptionsController {
@Bean
public DispatcherServlet dispatcherServlet() {
DispatcherServlet servlet = new DispatcherServlet();
servlet.setDispatchOptionsRequest(true);
return servlet;
}
public static ResponseEntity<Void> allows(HttpMethod[] methods) {
HttpHeaders headers = new HttpHeaders();
Set<HttpMethod> allow = new HashSet<>();
for(HttpMethod method: methods){
allow.add(method);
}
headers.setAllow(allow);
return new ResponseEntity<>(headers, HttpStatus.OK);
}
@RequestMapping(method = RequestMethod.OPTIONS)
ResponseEntity<Void> getProposalsOptions() {
HttpMethod[] methods = new HttpMethod[5];
methods[0] = HttpMethod.GET;
methods[1] = HttpMethod.PUT;
methods[2] = HttpMethod.POST;
methods[3] = HttpMethod.DELETE;
methods[4] = HttpMethod.OPTIONS;
return allows(methods);
}
}
POST控制器:
@Controller
public class PostController {
@Inject
private UserRepository users;
@RequestMapping(value = "/user", method = RequestMethod.POST)
public @ResponseBody void insertUser(@RequestBody final User user) {
users.save(user);
}
}
我做错了什么?
答案 0 :(得分:2)
正如@ Lurk21已经暗示的那样,您的问题是浏览器强制执行same-origin policy的结果。默认情况下,它禁止JavaScript代码向除“加载”之外的“源”发出HTTP请求。由于端口是起源的一部分,http://localhost
和http://localhost:8080
被视为不同的起源,这会导致问题。
但是,服务器可以通过发送带有OPTIONS
个请求响应的所谓Crosss-Origin Resource Sharing (CORS)标头,有选择地允许来自其他来源的请求。这就是您在浏览器开发人员工具中看到此类请求的原因。由于您的服务器响应不包含任何CORS标头,因此浏览器假定此URL不允许跨源请求并中止请求。
要解决此问题,请使用OPTIONS
响应发送以下标题:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, PUT, POST, DELETE
您还可以插入要允许来自的特定来源,而不是*
。有关您可能需要的其他标头和其他详细信息,请参阅MDN上的CORS文档(链接到上面)。
答案 1 :(得分:0)
问题在于相同原产地政策的规则&#39;。也许可能以某种方式用jsonp绕过它,但我还是需要在prod中反向代理,所以我将它添加到我的开发环境中并且它有效。