Backbone: navigation() с пробелом в URL запускает маршрут, даже если {trigger:false} в Firefox

Созданный на 27 нояб. 2014  ·  8Комментарии  ·  Источник: jashkenas/backbone

Рассмотрим этот пример:

$(function(){
var AppRouter = Backbone.Router.extend({

    routes: {
        '(count/:count)': 'home',
    },

    home: function(currCount) {
        var counter = 0;
        var thisObj = this;

        $("body").html($("<p>Click me</p>").on('click', function() {
            console.log("clicked "+counter);
            counter++;
            thisObj.navigate('count/'+counter, {trigger:false, replace: true});
        }));

        console.log('home route: '+currCount);    
    },
});

window.app = new AppRouter();
Backbone.history.start();
});

Это должно регистрировать «home route: null», а затем продолжать регистрировать «click #» для каждого нажатия «Click me».

Теперь сделайте одну небольшую модификацию. Добавьте пробел к URL-адресу в navigation():

thisObj.navigate('count/ '+counter, {trigger:false, replace: true});

Попробуйте еще раз, и вы обнаружите, что этот «домашний маршрут: #» также начнет регистрироваться, и счетчик будет сбрасываться _два раза из каждых трех кликов_.

Это версия 1.1.2, и я тестирую последнюю версию Firefox 33.1. У меня нет этой проблемы в Chrome - это может быть связано с тем, что Chrome может что-то делать для кодирования пробелов в URL-адресе. Хотя я не уверен.

Я понимаю, что символ пробела не должен быть в URL-адресе в первую очередь, но такое поведение является странным и должно быть, по крайней мере, задокументировано. (т.е. «навигационная функция () может вести себя не так, как ожидалось, с URL-адресами, содержащими пробелы (или другие небезопасные символы??)»).

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

Самый полезный комментарий

Вот что я обнаружил. В Firefox, если вы отметите переменную this.location.href, все пробелы в переменной будут закодированы в %20. Chrome (и, предположительно, IE) оставляет их как пробелы. Это проблема в Backbone, поскольку, когда вы переходите к навигации, «checkUrl()» сравнивает «this.fragment» с возвращаемым значением «this.getFragment()», чтобы определить, следует ли вызывать «this. loadUrl()", если они не совпадают. this.getFragment() возвращает значение this.location.href с %20 вместо любых пробелов в Firefox (или любых кодировок, если на то пошло). this.fragment возвращает декодированный эквивалент. this.fragment остается декодированным, независимо от того, используете ли вы encodeURI() в своих URL-адресах, потому что в функции «navigate()» this.fragment назначается путем вызова «this.decodeFragment()» для переданного URL-адреса. in, удаляя любые попытки принудительного кодирования.

Поэтому, если this.fragment всегда является декодированным URL-адресом из-за использования this.decodeFragment(), и URL-адрес содержит любые символы, которые может изменить encodeURI() (в данном случае пробелы), он никогда не будет соответствовать возвращаемому значению этого .getFragment() в Firefox, поскольку Firefox кодирует значение this.location.href, тогда как другие браузеры этого не делают. Поскольку эти два значения не совпадают, this.loadUrl() вызывается в checkUrl(), независимо от того, является ли параметр триггера в router.navigate истинным или ложным.

Предварительное исправление (предварительное исчерпывающее тестирование) будет состоять в том, чтобы изменить возвращаемое значение метода «getHash()» следующим образом:

return match ? this.decodeFragment(match[1].replace(pathStripper, '')) : '';

Все 8 Комментарий

Привет @chaimpeck! Спасибо, что сообщили об этом.

К сожалению, мне не удалось воспроизвести его с помощью приведенного выше кода. Я пробовал последние версии Chrome и Firefox как с основной веткой, так и с выпуском 1.1.2. Не могли бы вы опубликовать рабочий пример в gist/bin/fiddle, на который я могу взглянуть?

У нас определенно были проблемы с кодированием/декодированием определенных символов в Firefox раньше, и я не сомневаюсь, что их больше. :смайлик:

На самом деле я видел точно такую ​​же проблему, но не могу поделиться своим кодом. Я посмотрю, смогу ли я смоделировать какой-нибудь тестовый код, чтобы воспроизвести это, но я обнаружил, что проблема определенно связана с браузером. Все современные версии IE и Chrome работают нормально, но, по крайней мере, в Firefox v31.5.0 (не спрашивайте, я ненавижу инфраструктуру, в которой мы застряли) он определенно срабатывает, даже не добавляя параметр триггера.

Вот что я обнаружил. В Firefox, если вы отметите переменную this.location.href, все пробелы в переменной будут закодированы в %20. Chrome (и, предположительно, IE) оставляет их как пробелы. Это проблема в Backbone, поскольку, когда вы переходите к навигации, «checkUrl()» сравнивает «this.fragment» с возвращаемым значением «this.getFragment()», чтобы определить, следует ли вызывать «this. loadUrl()", если они не совпадают. this.getFragment() возвращает значение this.location.href с %20 вместо любых пробелов в Firefox (или любых кодировок, если на то пошло). this.fragment возвращает декодированный эквивалент. this.fragment остается декодированным, независимо от того, используете ли вы encodeURI() в своих URL-адресах, потому что в функции «navigate()» this.fragment назначается путем вызова «this.decodeFragment()» для переданного URL-адреса. in, удаляя любые попытки принудительного кодирования.

Поэтому, если this.fragment всегда является декодированным URL-адресом из-за использования this.decodeFragment(), и URL-адрес содержит любые символы, которые может изменить encodeURI() (в данном случае пробелы), он никогда не будет соответствовать возвращаемому значению этого .getFragment() в Firefox, поскольку Firefox кодирует значение this.location.href, тогда как другие браузеры этого не делают. Поскольку эти два значения не совпадают, this.loadUrl() вызывается в checkUrl(), независимо от того, является ли параметр триггера в router.navigate истинным или ложным.

Предварительное исправление (предварительное исчерпывающее тестирование) будет состоять в том, чтобы изменить возвращаемое значение метода «getHash()» следующим образом:

return match ? this.decodeFragment(match[1].replace(pathStripper, '')) : '';

Все еще нужно с последней версией, так что спасибо!

У меня такая же проблема при попытке использовать нестандартные символы в URL-адресе, в моем случае åäö (символы шведского алфавита). Последняя версия Chrome и Backbone.

Решение sjmiller85 сработало и для меня. Огромное спасибо!

@ sjmiller85 Какое у вас было решение? Я не совсем понимаю, что следует использовать для «pathStripper». Это регулярное выражение?
Изменить: это работает в моей ситуации. см. https://github.com/jashkenas/backbone/pull/3955/files
getHash: function (t) { var e = (t || this).location.href.match(/#(.*)$/); return e ? e[1] : "" }

@Aggror pathStripper, согласно документации, является кэшированным регулярным выражением для удаления URL-адресов из хэша.

// Cached regex for stripping urls of hash.
var pathStripper = /#.*$/;

Так что это эквивалент вашего решения, только более аккуратный и эффективный :)

избегайте одновременного добавления одного и того же хэша на ваш маршрутизатор, а также позаботьтесь о начальном состоянии, я покажу вам код
(для обработки начального случая) (для предотвращения добавления одновременных одинаковых маршрутов)
если ( маршруты.длина === 1 || маршруты[маршруты.длина-1] === getHash() ) {
вернуть ложь;
}
еще{
маршруты.push(getHash())
};

Была ли эта страница полезной?
0 / 5 - 0 рейтинги