web-dev-qa-db-fra.com

Comment tester si une chaîne URL est absolue ou relative?

Comment puis-je tester une URL s'il s'agit d'un chemin relatif ou absolu en Javascript ou jQuery? Je veux gérer en conséquence selon que l'URL transmise est un chemin local ou externe.

if (urlString starts with http:// or https://)
 //do this
60
TruMan1
var pat = /^https?:\/\//i;
if (pat.test(urlString))
{
    //do stuff
}

Pour les URL relatives au protocole, utilisez cette expression régulière:

/^https?:\/\/|^\/\//i

29
strah

VITE

Si vous avez seulement besoin de tester http:// ou https:// alors la façon la plus efficace est:

if (urlString.indexOf('http://') === 0 || urlString.indexOf('https://') === 0)

UNIVERSEL

Cependant, je suggérerais une approche plus universelle, non sensible à la casse, agnostique au protocole:

var r = new RegExp('^(?:[a-z]+:)?//', 'i');
r.test('http://example.com'); // true - regular http absolute URL
r.test('HTTP://EXAMPLE.COM'); // true - HTTP upper-case absolute URL
r.test('https://www.exmaple.com'); // true - secure http absolute URL
r.test('ftp://example.com/file.txt'); // true - file transfer absolute URL
r.test('//cdn.example.com/lib.js'); // true - protocol-relative absolute URL
r.test('/myfolder/test.txt'); // false - relative URL
r.test('test'); // false - also relative URL

Expliquez le RegExp

^(?:[a-z]+:)?//

^ - début de la chaîne
(?: - début d'un groupe non capturé
[a-z]+ - tout caractère de 'a' à 'z' 1 fois ou plus
: - chaîne (caractère deux-points)
)? - fin du groupe non capturé. Groupe apparaissant 0 ou 1 fois
// - chaîne (deux caractères de barre oblique)
'i' - indicateur non sensible à la casse

137
Geo

Utilisez une expression régulière:

if (/^(?:[a-z]+:)?\/\//i.test(url))
17
SLaks

Réponse originale

Un contrôle très très rapide et très flexible est:

if (url.indexOf('://') > 0 || url.indexOf('//') === 0 ) {
    // URL is absolute; either "http://example.com" or "//example.com"
} else {
    // URL is relative
}

Cela reconnaîtra une URL absolue, si:

  • L'URL contient ": //" n'importe où après le premier caractère, ou
  • L'URL commence par "//" (relatif au protocole)

  • Aucun regex.
  • Aucune jQuery ou autre dépendance.
  • Aucun nom de protocole codé en dur qui rend la condition sensible à la casse.
  • Aucune manipulation de chaîne (par exemple toLowerCase ou similaire).
  • Seules les vérifications pour "relatif ou absolu" mais ne fait aucun autre contrôle de validité peuvent être utilisées pour les URL Web ou tout protocole interne.

Mise à jour 1 (exemple de fonction complète)

Voici une fonction rapide qui retourne vrai/faux pour l'URL donnée:

function isUrlAbsolute(url) { 
    return (url.indexOf('://') > 0 || url.indexOf('//') === 0);
}

Et même dans ES6:

const isUrlAbsolute = (url) => (url.indexOf('://') > 0 || url.indexOf('//') === 0)

Mise à jour 2 (URL dans les paramètres d'URL)

Pour adresser en outre des URL au format /redirect?target=http://example.org Je recommande d'utiliser ce code:

function isUrlAbsolute(url) {
    if (url.indexOf('//') === 0) {return true;} // URL is protocol-relative (= absolute)
    if (url.indexOf('://') === -1) {return false;} // URL has no protocol (= relative)
    if (url.indexOf('.') === -1) {return false;} // URL does not contain a dot, i.e. no TLD (= relative, possibly REST)
    if (url.indexOf('/') === -1) {return false;} // URL does not contain a single slash (= relative)
    if (url.indexOf(':') > url.indexOf('/')) {return false;} // The first colon comes after the first slash (= relative)
    if (url.indexOf('://') < url.indexOf('.')) {return true;} // Protocol is defined before first dot (= absolute)
    return false; // Anything else must be relative
}

Et la même chose sous forme abrégée et ES 6

// Traditional JS, shortened
function isUrlAbsolute(url) {
    return url.indexOf('//') === 0 ? true : url.indexOf('://') === -1 ? false : url.indexOf('.') === -1 ? false : url.indexOf('/') === -1 ? false : url.indexOf(':') > url.indexOf('/') ? false : url.indexOf('://') < url.indexOf('.') ? true : false;
}

// ES 6
const isUrlAbsolute = (url) => (url.indexOf('//') === 0 ? true : url.indexOf('://') === -1 ? false : url.indexOf('.') === -1 ? false : url.indexOf('/') === -1 ? false : url.indexOf(':') > url.indexOf('/') ? false : url.indexOf('://') < url.indexOf('.') ? true : false)

Voici quelques cas de test:

// Test
console.log( isUrlAbsolute('http://stackoverflow.com') ) // -> true
console.log( isUrlAbsolute('//stackoverflow.com') ) // -> true
console.log( isUrlAbsolute('stackoverflow.com') ) // -> false
console.log( isUrlAbsolute('Ftp://example.net') ) // -> true
console.log( isUrlAbsolute('/redirect?target=http://example.org') ) // -> false

Mise à jour 3 (clarifier les URL relatives)

J'ai vu quelques commentaires sur une sortie non valide:

  • La solution renvoie false pour localhost
  • La réponse échoue le http:example.com

Cependant, ces URL sont en effet des URL relatives . C'est facile à tester:

  1. Créez des dossiers sur votre racine locale d'hôte, dites a/b/c/
  2. Créez un fichier index.html et placez-y le lien suivant: <a href="localhost">test</a>
  3. Ouvrez la page d'index dans votre navigateur: http: //localhost/a/b/c/index.html et cliquez sur le lien. Vous terminerez sur http: // localhost/a/b/c/localhost (et non sur http: // localhost )
  4. La même chose se produit lors du placement du lien http:example.com dans votre fichier index.html. Vous vous retrouvez sur http: //localhost/a/b/c/example.com au lieu de http://example.com
14
Philipp

De nos jours, lorsque de nombreux services utilisent RL relative au protocole (par exemple // cdn.example.com/libary.js), cette méthode est plus sûre:

var isAbsolute = new RegExp('^([a-z]+://|//)', 'i');

if (isAbsolute.test(urlString)) {
  // go crazy here
}
9
rgtk

Approche URI encore plus compatible RFC universelle:

(?:^[a-z][a-z0-9+.-]*:|\/\/)explication regex

Les autres solutions répertoriées ici échoueraient pour des liens comme mailto:[email protected]

La RFC 3986 définit un schéma comme:

scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )

3.1. Schéma https://tools.ietf.org/html/rfc3986#section-3.1

Bien que l'URL relative au protocole soit techniquement valide conformément à la section 4.2, Paul Irish a fait marche arrière et considère qu'il s'agit d'un anti-modèle. Voir http://www.paulirish.com/2010/the-protocol-relative-url/

4.2. Référence relative http://tools.ietf.org/html/rfc3986#section-4.2

Si vous souhaitez utiliser l'expression régulière sans utiliser d'URL relative au protocole:

^[a-z][a-z0-9+.-]*:

Pour voir une liste complète d'autres types de valises uri Edge valides, consultez la liste ici: https://en.wikipedia.org/wiki/URI_scheme

8
Evan

N'utilisez pas de trucs de bas niveau comme regexp etc. Ces choses ont été résolues par tant d'autres personnes. Surtout les cas Edge.

Jetez un œil à RI.js , il devrait faire le travail: http://medialize.github.io/URI.js/docs.html#is

var uri = new URI("http://example.org/");
uri.is("absolute") === true;
5
koppor
var external = RegExp('^(https?:)?//');
if(external.test(el)){
    // do something
}

MODIFIER:

Avec l'expression régulière suivante, vous pouvez même vérifier si le lien va vers le même domaine ou vers un domaine externe:

var external = RegExp('^((f|ht)tps?:)?//(?!' + location.Host + ')');
if(external.test(el)){
    // do something
}
5
davids

Selon vos besoins, je pense qu'un moyen plus fiable de le déterminer est d'utiliser interface URL intégrée pour construire quelques objets URL et comparer les origines.

new URL(document.baseURI).Origin === new URL(urlToTest, document.baseURI).Origin;

Cela permet au navigateur d'analyser et de comprendre tout cela pour vous, sans avoir à vous soucier des effets secondaires des coques Edge.

2
Brad

La fonction suivante sera appelée lorsqu'un clic se produit même sur un lien hypertexte, c'est-à-dire une balise 'a' si la balise contient une URL sera relative ou contient le même hôte, alors cette nouvelle page sera chargée dans le même onglet du navigateur si elle contient une URL différente, la page se chargera nouvel onglet du navigateur

jQuery(document).ready(function() {
    $('a').click(function(){

        var a = this;
        var a_href = $(this).attr('href');
        var regex = new RegExp('^(?:[a-z]+:)?//', 'i');     

        if(a.Host == location.Host || regex.test(a_href) == false){
            a.target = '_self';
        }else{
            a.target = '_blank';
        }
    }); 
});
1
Prajyot
var adress = 'http://roflmao.com';
if (adress.substr(0,7) == 'http://' || adress.substr(0,8) == 'https://') {
    //
}
1
OptimusCrime

Voici une approche à toute épreuve du problème:

Laissez le navigateur gérer tout pour nous. Pas besoin de regex compliqué/sujet aux erreurs.

const isAbsoluteUrl = (url) => {
  const link = document.createElement('a');
  link.href = url;
  return link.Origin + link.pathname + link.search + link.hash === url;
};

Malheureusement, ne fonctionne pas dans un environnement nodejs.

1
Etienne Martin