Backbone: navigue() avec un espace dans l'url déclenche la route même lorsque {trigger:false} dans Firefox

Créé le 27 nov. 2014  ·  8Commentaires  ·  Source: jashkenas/backbone

Considérez cet exemple :

$(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();
});

Cela devrait enregistrer "home route: null" puis continuer à enregistrer "click #" pour chaque clic sur "Click me".

Maintenant, faites une petite modification. Ajoutez un espace à l'url dansnaviguer() :

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

Réessayez et vous constaterez que cette "route locale : #" commencera également à être enregistrée, et le compteur réinitialisera _deux clics sur trois_.

C'est dans la version 1.1.2 et je teste sur le dernier Firefox 33.1. Je n'ai pas ce problème dans Chrome - c'est peut-être parce que Chrome fait peut-être quelque chose pour encoder les espaces dans l'URL. Je ne suis pas sûr cependant.

Je me rends compte que le caractère d'espace ne devrait pas être dans une URL en premier lieu, mais ce comportement est étrange et devrait à tout le moins être documenté. (c'est-à-dire "Le browser() peut ne pas se comporter comme prévu avec des URL contenant des espaces (ou d'autres caractères non sécurisés ??).")

Je ne sais pas s'il existe une solution simple à ce problème, mais j'espère qu'au moins en documentant ce bogue, je ferai gagner du temps aux autres développeurs en essayant de le traquer.

invalid

Commentaire le plus utile

Voici ce que j'ai découvert. Dans Firefox, si vous cochez la variable "this.location.href", tous les espaces blancs dans la variable sont encodés en %20. Chrome (et vraisemblablement IE) les laisse sous forme d'espaces blancs. C'est un problème dans Backbone, car lorsque vous allez naviguer, "checkUrl()" fait une comparaison de "this.fragment" avec la valeur renvoyée de "this.getFragment()" pour déterminer s'il faut ou non appeler "this. loadUrl()", s'ils ne correspondent pas. this.getFragment() renvoie la valeur de this.location.href, avec les %20 à la place de tous les espaces dans Firefox (ou de tout encodage d'ailleurs). this.fragment renvoie un équivalent décodé. this.fragment reste décodé, que vous utilisiez ou non encodeURI() sur vos URL, car dans la fonction "navigate()", this.fragment est attribué en appelant "this.decodeFragment()" sur l'URL qui est transmise in, supprimant toute tentative de forcer l'encodage.

Par conséquent, si this.fragment est toujours une URL décodée en raison de l'utilisation de this.decodeFragment(), et que l'URL contient des caractères que encodeURI() changerait (dans ce cas, des espaces), il ne correspondra jamais à la valeur renvoyée de this .getFragment() dans Firefox, car Firefox encode la valeur de this.location.href, alors que les autres navigateurs ne le font pas. Étant donné que ces deux valeurs ne correspondent pas, this.loadUrl() est appelé dans checkUrl(), que le paramètre de déclenchement dans router.navigate soit vrai ou faux.

Le correctif préliminaire (test pré-exhaustif) serait de changer la valeur de retour de la méthode "getHash()" pour lire :

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

Tous les 8 commentaires

Salut @chaimpeck ! Merci d'avoir signalé cela.

Malheureusement, je n'ai pas pu le reproduire en utilisant le code ci-dessus. J'ai essayé les derniers Chrome et Firefox avec la branche principale et la version 1.1.2. Cela vous dérangerait-il de publier un exemple de travail dans un gist/bin/fiddle que je puisse consulter ?

Nous avons certainement eu des problèmes avec l'encodage/décodage de caractères spécifiques dans Firefox auparavant et je ne doute pas qu'il y en ait plus. :smiley:

En fait, j'ai vu exactement le même problème, mais je ne parviens pas à partager mon code. Je vais voir si je peux simuler un code de test pour reproduire cela, mais j'ai découvert que le problème est très certainement basé sur le navigateur. Toutes les versions modernes d'IE et de Chrome fonctionnent bien, mais au moins sur Firefox v31.5.0 (ne demandez pas, je déteste l'infrastructure sur laquelle nous sommes bloqués), il se déclenche définitivement sans même ajouter l'option de déclenchement.

Voici ce que j'ai découvert. Dans Firefox, si vous cochez la variable "this.location.href", tous les espaces blancs dans la variable sont encodés en %20. Chrome (et vraisemblablement IE) les laisse sous forme d'espaces blancs. C'est un problème dans Backbone, car lorsque vous allez naviguer, "checkUrl()" fait une comparaison de "this.fragment" avec la valeur renvoyée de "this.getFragment()" pour déterminer s'il faut ou non appeler "this. loadUrl()", s'ils ne correspondent pas. this.getFragment() renvoie la valeur de this.location.href, avec les %20 à la place de tous les espaces dans Firefox (ou de tout encodage d'ailleurs). this.fragment renvoie un équivalent décodé. this.fragment reste décodé, que vous utilisiez ou non encodeURI() sur vos URL, car dans la fonction "navigate()", this.fragment est attribué en appelant "this.decodeFragment()" sur l'URL qui est transmise in, supprimant toute tentative de forcer l'encodage.

Par conséquent, si this.fragment est toujours une URL décodée en raison de l'utilisation de this.decodeFragment(), et que l'URL contient des caractères que encodeURI() changerait (dans ce cas, des espaces), il ne correspondra jamais à la valeur renvoyée de this .getFragment() dans Firefox, car Firefox encode la valeur de this.location.href, alors que les autres navigateurs ne le font pas. Étant donné que ces deux valeurs ne correspondent pas, this.loadUrl() est appelé dans checkUrl(), que le paramètre de déclenchement dans router.navigate soit vrai ou faux.

Le correctif préliminaire (test pré-exhaustif) serait de changer la valeur de retour de la méthode "getHash()" pour lire :

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

Toujours nécessaire avec la dernière version alors merci !

J'ai le même problème lorsque j'essaie d'utiliser des caractères non standard dans l'URL, dans mon cas åäö (caractères qui sont dans l'alphabet suédois). Dernière version de Chrome et Backbone.

La solution de sjmiller85 a également fonctionné pour moi. Merci beaucoup !

@ sjmiller85 Quelle était votre solution ici ? Je ne comprends pas entièrement ce qui doit être utilisé pour 'pathStripper'. Est-ce une expression régulière ?
Edit: cela fonctionne dans ma situation. voir https://github.com/jashkenas/backbone/pull/3955/files
getHash: function (t) { var e = (t || this).location.href.match(/#(.*)$/); return e ? e[1] : "" }

@Aggror pathStripper est, selon la documentation, une expression régulière en cache pour supprimer les URL de hachage.

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

C'est donc l'équivalent de votre solution, en plus propre et efficace :)

évitez d'ajouter simultanément le même hachage à votre routeur et prenez également soin de l'état initial, je vais vous montrer un code
(pour gérer le cas initial) (pour éviter d'ajouter simultanément les mêmes routes)
if ( routes.length === 1 || routes[routes.length-1] === getHash() ) {
retourner faux ;
}
autre{
routes.push(getHash())
} ;

Cette page vous a été utile?
0 / 5 - 0 notes