Backbone.js执行OPTIONS而不是POST

时间:2014-01-06 16:33:07

标签: javascript jquery spring rest backbone.js

我有一个骨干客户端应用程序和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);
    }
}

我做错了什么?

2 个答案:

答案 0 :(得分:2)

正如@ Lurk21已经暗示的那样,您的问题是浏览器强制执行same-origin policy的结果。默认情况下,它禁止JavaScript代码向除“加载”之外的“源”发出HTTP请求。由于端口是起源的一部分,http://localhosthttp://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中反向代理,所以我将它添加到我的开发环境中并且它有效。