Добавление заголовка HTTP Basic Authentication в функцию синхронизации Backbone.js предотвращает обновление модели при сохранении()

Я работаю над веб-приложением, основанным на спокойном API, написанном с помощью платформы Python CherryPy. Я начал писать пользовательский интерфейс с комбинации jQuery и серверных шаблонов, но в конце концов переключился на Backbone.js, потому что jQuery вышел из-под контроля.

К сожалению, у меня возникли проблемы с синхронизацией моих моделей с сервером. Вот быстрый пример из моего кода:

$(function() {
    var User = Backbone.Model.extend({
        defaults: {
            id: null,
            username: null,
            token: null,
            token_expires: null,
            created: null
        },

        url: function() {
            return '/api/users';
        },

        parse: function(response, options) {
            console.log(response.id);
            console.log(response.username);
            console.log(response.token);
            console.log(response.created);
            return response;
        }
    });

    var u = new User();
    u.save({'username':'asdf', 'token':'asdf'}, {
        wait: true,
        success: function(model, response) {
            console.log(model.get('id'));
            console.log(model.get('username'));
            console.log(model.get('token'));
            console.log(model.get('created'));
        }
    });
});

Как вы, наверное, поняли, идея здесь в том, чтобы зарегистрировать нового пользователя в сервисе. Когда я вызываю u.save();, Backbone действительно отправляет запрос POST на сервер. Вот соответствующие биты:

Запрос:

Request URL: http://localhost:8080/api/users
Request Method: POST
Request Body: {"username":"asdf","token":"asdf","id":null,"token_expires":null,"created":null}

Ответ:

Status Code: HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 109
Response Body: {"username": "asdf", "created": "2013-02-07T13:11:09.811507", "token": null, "id": 14, "token_expires": null}

Как видите, сервер успешно обрабатывает запрос и отправляет обратно id и значение created. Но по какой-то причине, когда мой код вызывает console.log(u.id);, я получаю null, а когда мой код вызывает console.log(u.created);, я получаю undefined.

tl;dr: Почему Backbone.js не сохраняет изменения в моих объектах после вызова save()?

Изменить: я изменил приведенный выше код, чтобы доступ к свойствам модели осуществлялся с помощью функции get в обратном вызове success. Это должно решить любые проблемы параллелизма с исходным кодом.

Я также добавил логирование консоли в функцию parse модели. Как ни странно, каждый из них undefined... Значит ли это, что Backbone.js не может разобрать мой ответ JSON?

Редактировать 2: несколько дней назад я обнаружил, что проблема была на самом деле в пользовательском заголовке, который я добавлял к каждому запросу, чтобы включить базовую аутентификацию HTTP. Подробности см. в этом ответе.


person MusikPolice    schedule 07.02.2013    source источник
comment
Ваш код выглядит нормально (за исключением того, что вы должны использовать Model.urlRoot вместо Model.url, но здесь проблема не в этом). В более ранних версиях вашего кода были проблемы, но вы абсолютно уверены, что точный код в вашем текущем редактировании по-прежнему не работает?   -  person jevakallio    schedule 20.02.2013


Ответы (4)


Этот код:

u.save();
console.log(u.id);
console.log(u.username);
console.log(u.token);
console.log(u.created);

Запускается немедленно... после этого запускать нечего и начинается ajax-запрос в очереди. Затем ответ приходит немного позже, и только в этот момент значения изменяются.

Также кажется, что эти свойства не находятся непосредственно в объекте, но асинхронная обработка сохранения по-прежнему сохраняется в том смысле, что вы не получите ожидаемых результатов, даже если вы исправите этот код, чтобы иметь console.log(u.get("id")) и т. д.

person Esailija    schedule 07.02.2013
comment
Ваше предложение использовать u.get(id) вместо u.id имеет большой смысл, но даже если я попытаюсь зарегистрировать эти свойства в успешном обратном вызове или в событии синхронизации модели, они останутся неустановленными, поэтому я думаю, что есть еще к проблеме. - person MusikPolice; 20.02.2013
comment
Я отредактировал код в исходном вопросе, чтобы включить ваши предложения... Он все еще не работает, и я в замешательстве. - person MusikPolice; 20.02.2013
comment
@MusikPolice, если вы определили функцию синтаксического анализа, вы несете ответственность за возврат проанализированной модели из ответа. Эта функция используется, когда ответ сервера не структурирован напрямую для создания модели из - person Esailija; 20.02.2013
comment
@MusikPolice, вы можете отлаживать его в функции синтаксического анализа вот так console.log( JSON.parse(JSON.stringify(response))) - person Esailija; 20.02.2013

Я разобрался с проблемой, хотя до сих пор не могу объяснить, почему это вообще проблема. Веб-приложение, которое я создаю, имеет процесс аутентификации, который требует, чтобы заголовок HTTP Basic Authentication передавался со всеми запросами.

Чтобы это работало с Backbone, я переопределил функцию Backbone.sync и изменил строка 1398, чтобы добавить заголовок.

Исходный код:

var params = {type: type, dataType: 'json'};

Измененный код:

var params = {
    type: type,
    dataType: 'json',
    headers: {
        'Authorization': getAuthHash()
    }
};

Функция getAuthHash() просто возвращает строку Base64, которая представляет соответствующую информацию для аутентификации.

По какой-то причине добавление этого заголовка приводит к сбою функций синхронизации/сохранения. Если я уберу его, все будет работать так, как вы могли бы ожидать.

Щедрость все еще открыта, и я с радостью вознагражу любого, кто может объяснить, почему это так, а также предоставить решение проблемы.

Изменить:

Похоже, проблема заключалась в том, что я добавлял заголовок к запросу. На Github есть хорошая небольшая библиотека JavaScript, , которая решает эту проблему, правильно добавляя заголовок HTTP Basic Auth. .

person MusikPolice    schedule 21.02.2013

Я проверил ваш код, он отлично работает для меня.

См. демо здесь, jsfiddle.net/yxkUD/

person Array out of bound    schedule 27.02.2013
comment
Извините, я не добавил дополнительную информацию о проблеме в вопрос. Дополнительные сведения см. в этом описании. - person MusikPolice; 27.02.2013

Попробуйте добавить собственный метод beforeSend в запрос ajax, чтобы добавить собственный заголовок.

Например: https://github.com/documentcloud/backbone/blob/master/backbone.js#L1424

person axelhzf    schedule 25.02.2013