Kann ich require ("path"). Join verwenden, um URLs sicher zu verketten?

128

Ist dies sicher zum require("path").joinVerketten von URLs, zum Beispiel:

require("path").join("http://example.com", "ok"); 
//returns 'http://example.com/ok'

require("path").join("http://example.com/", "ok"); 
//returns 'http://example.com/ok'

Wenn nicht, wie würden Sie dies vorschlagen, ohne Code voller Wenns zu schreiben?

Renato Gama
quelle
3
Siehe auch github.com/joyent/node/issues/2216
Colonel Panic
5
Falls jemand will path.join, aber vermeiden Sie Probleme unter Windows verwenden: path.posix.join('/one/two/three', 'four') // '/one/two/three/four, path.posix.join('/one/two/three/', 'four') // '/one/two/three/four,path.posix.join('/one/two/three/', '/four') // '/one/two/three/four
Timothy Zorn
5
@ TimothyZorn Das Problem ist, dass wenn Sie so etwas tun path.posix.join('http://localhost:9887/one/two/three/', '/four'), der Join einen der doppelten Schrägstriche inhttp://
Max Alexander
Ahh, ja - guter Punkt. In diesen Szenarien möchten Sie so etwas tun 'http://localhost:9887/one/two/three/'.replace(/^\/+|\/+$/, '') + '/' + '/four'.replace(/^\/+|\/+$/, '')und können dies tun, String.prototype.trimSlashes = function() { return this.replace(/^\/+|\/+$/, ''); }wenn Sie den regulären Ausdruck nicht immer wieder eingeben möchten . stackoverflow.com/a/22387870/2537258
Timothy Zorn
oder['http://localhost:9887/one/two/three/', '/four'].map((part) => part. replace(/^\/+|\/+$/, '')).join('/')
Timothy Zorn

Antworten:

141

Nein. path.join() Gibt bei Verwendung mit URLs falsche Werte zurück.

Es klingt wie du willst url.resolve. Aus den Knotendokumenten :

url.resolve('/one/two/three', 'four')         // '/one/two/four'
url.resolve('http://example.com/', '/one')    // 'http://example.com/one'
url.resolve('http://example.com/one', '/two') // 'http://example.com/two'

Bearbeiten: Wie Andreas in einem Kommentar richtig hervorhebt, url.resolvewürde nur helfen, wenn das Problem so einfach ist wie im Beispiel. url.parseDies gilt auch für diese Frage, da über das URLObjekt konsistent und vorhersehbar formatierte Felder zurückgegeben werden , wodurch der Bedarf an "Code voller Ifs" verringert wird.

Matthew Bakaitis
quelle
1
Obwohl nicht genau das, wonach ich gesucht habe, löst dies auch mein Problem. Danke fürs Helfen!
Renato Gama
6
@AndreasHultgren der erste Kommentar ist korrekt. Wenn das Beispiel url.resolve('/one/two/three/', 'four')wäre, wäre die Ausgabe 'one/two/three/four'.
Tavnab
3
Falls jemand will path.join, aber vermeiden Sie Probleme unter Windows verwenden: path.posix.join('/one/two/three', 'four') // '/one/two/three/four, path.posix.join('/one/two/three/', 'four') // '/one/two/three/four,path.posix.join('/one/two/three/', '/four') // '/one/two/three/four
Timothy Zorn
2
Die Kommentare sind falsch, url.resolve('/one/two/three', 'four') // '/one/two/four'in der Antwort ist richtig
Jonathan.
2
Beachten Sie auch, dass url.resolve()nur 2 Argumente verwendet werden, wobei path.join()eine beliebige Zahl verwendet wird. Je nachdem, was Sie tun, müssen Sie möglicherweise Anrufe verschachteln, z. B.url.resolve(url.resolve(SERVER_URL, pagePath), queryString)
Molomby
47

Nein, Sie sollten keine path.join()URL-Elemente verknüpfen.

Dafür gibt es jetzt ein Paket. Anstatt das Rad neu zu erfinden, alle Ihre eigenen Tests zu schreiben, Fehler zu finden, sie zu beheben, weitere Tests zu schreiben, einen Randfall zu finden, in dem es nicht funktioniert usw., könnten Sie dieses Paket verwenden.

URL-Join

https://github.com/jfromaniello/url-join

Installieren

npm install url-join

Verwendung

var urljoin = require('url-join');

var fullUrl = urljoin('http://www.google.com', 'a', '/b/cd', '?foo=123');

console.log(fullUrl);

Drucke:

" http://www.google.com/a/b/cd?foo=123 "

Stein
quelle
1
Dies. Das ist fantastisch. Danke dir.
Dudewad
6

Als ich PATH zum Verketten von URL-Teilen ausprobiert habe, sind Probleme aufgetreten. PATH.joinStreifen '//' bis '/' und auf diese Weise wird eine absolute URL ungültig (z. B. http: // ... -> http: / ...). Für mich war eine schnelle Lösung:

baseurl.replace(/\/$/,"") + '/' + path.replace(/^\//,"") )

oder mit der von Colonel Panic veröffentlichten Lösung:

[pathA.replace(/^\/|\/$/g,""),pathB.replace(/^\/|\/$/g,"")].join("/")
Peter
quelle
Was ist, wenn ich versuche, eine root-relative URL wie diese zu erstellen : /assets/foo? Daraus ergibt sich eine URL, die sich auf den aktuellen Pfad bezieht assets/foo.
Andrey Mikhaylov - lolmaus
5

Nein! Unter Windows path.joinwerden Backslashes hinzugefügt. HTTP-URLs sind immer Schrägstriche.

Wie wäre es mit

> ["posts", "2013"].join("/")
'posts/2013'
Oberst Panik
quelle
Gute Idee, aber was ist, wenn das erste Argument am Ende bereits einen Schrägstrich enthält? zB .: ["posts/", "2013"].join("/")?
Renato Gama
1
@ RenatoGama posts//2013ist immer noch eine gültige URL.
Goodwine
2
^ Das funktioniert nicht in allen Domänen, obwohl es sich um eine gültige URI handelt.
BingeBoy
2
Insbesondere ignoriert Node's Express keine überflüssigen Schrägstriche für das Routing.
Perseiden
1
Falls jemand will path.join, aber vermeiden Sie Probleme unter Windows verwenden: path.posix.join('/one/two/three', 'four') // '/one/two/three/four, path.posix.join('/one/two/three/', 'four') // '/one/two/three/four,path.posix.join('/one/two/three/', '/four') // '/one/two/three/four
Timothy Zorn
5

Wir machen es so:

var _ = require('lodash');

function urlJoin(a, b) {
  return _.trimEnd(a, '/') + '/' + _.trimStart(b, '/');
}
Peter Dotchev
quelle
4

Wenn Sie lodash verwenden , können Sie diesen einfachen Oneliner verwenden:

// returns part1/part2/part3
['part1/', '/part2', '/part3/'].map((s) => _.trim(s, '/')).join('/')

inspiriert von @Peter Dotchevs Antwort

MK
quelle
3

Das benutze ich:

function joinUrlElements() {
  var re1 = new RegExp('^\\/|\\/$','g'),
      elts = Array.prototype.slice.call(arguments);
  return elts.map(function(element){return element.replace(re1,""); }).join('/');
}

Beispiel:

url = joinUrlElements(config.mgmtServer, '/v1/o/', config.org, '/apps');
Cheeso
quelle
Was ist, wenn ich versuche, eine root-relative URL wie diese zu erstellen : /assets/foo? Daraus ergibt sich eine URL, die sich auf den aktuellen Pfad bezieht assets/foo.
Andrey Mikhaylov - lolmaus
1
einen Schrägstrich voranstellen? Ich meine, es ist eine einfache Überprüfung; Sie können es selbst hinzufügen.
Cheeso
3
So fängt es an ... Als nächstes wissen Sie, dass Sie mehr als 8 Stunden damit verbracht haben, Randfälle zu finden, die nicht funktionieren, und sie im Verlauf Ihres Projekts zu beheben.
Stein
3

Wenn Sie Angular verwenden, können Sie Location verwenden :

import { Location } from '@angular/common';
// ...
Location.joinWithSlash('beginning', 'end');

Funktioniert jedoch nur mit 2 Argumenten, sodass Sie bei Bedarf Aufrufe verketten oder eine Hilfsfunktion schreiben müssen, um dies zu tun.

Qortex
quelle
2

Das WHATWG URL - Objekt Konstruktor hat eine (input, base)Version, und das inputkann mit relativ sein /, ./, ../. Kombinieren Sie dies mit path.posix.joinund Sie können alles tun:

const {posix} = require ("path");
const withSlash = new URL("https://example.com:8443/something/");
new URL(posix.join("a", "b", "c"), withSlash).toString(); // 'https://example.com:8443/something/a/b/c'
new URL(posix.join("./a", "b", "c"), withSlash).toString(); // 'https://example.com:8443/something/a/b/c'
new URL(posix.join("/a", "b", "c"), withSlash).toString(); // 'https://example.com:8443/a/b/c'
new URL(posix.join("../a", "b", "c"), withSlash).toString(); // 'https://example.com:8443/a/b/c'
const noSlash = new URL("https://example.com:8443/something");
new URL(posix.join("./a", "b", "c"), noSlash).toString(); // 'https://example.com:8443/a/b/c'
Codierer
quelle
0

Benutzerdefinierte Typoskript-Lösung:

export function pathJoin(parts: string[], sep: string) {
  return parts
    .map(part => {
      const part2 = part.endsWith(sep) ? part.substring(0, part.length - 1) : part;
      return part2.startsWith(sep) ? part2.substr(1) : part2;
    })
    .join(sep);
}

expect(pathJoin(['a', 'b', 'c', 'd'], '/')).toEqual('a/b/c/d');
expect(pathJoin(['a/', '/b/', 'c/', 'd'], '/')).toEqual('a/b/c/d');
expect(pathJoin(['http://abc.de', 'users/login'], '/')).toEqual('http://abc.de/users/login');
Patrick Wozniak
quelle
0

Meine Lösung

path.join(SERVER_URL, imageAbsolutePath).replace(':/','://');

Bearbeiten: Wenn Sie Windows-Umgebungen unterstützen möchten

path.join(SERVER_URL, imageAbsolutePath).replace(/\\/g,'/').replace(':/','://');

Die zweite Lösung ersetzt alle Backslashes, sodass URL-Teile wie Querystring und Hash ebenfalls geändert werden können, das Thema jedoch nur den URL-Pfad verbindet, sodass ich es nicht als Problem betrachte.

Killy
quelle
0

Es gibt andere funktionierende Antworten, aber ich ging mit den folgenden. Eine kleine Kombination aus path.join und URL.

const path = require('path');
//
const baseUrl = 'http://ejemplo.mx';
// making odd shaped path pieces to see how they're handled.
const pieces = ['way//', '//over/', 'there/'];
//
console.log(new URL(path.join(...pieces), baseUrl).href);
// http://ejemplo.mx/way/over/there/

// path.join expects strings. Just an example how to ensure your pieces are Strings.
const allString = ['down', 'yonder', 20000].map(String);
console.log(new URL(path.join(...allString), baseUrl).href);
// http://ejemplo.mx/down/yonder/20000
Neil Guy Lindberg
quelle
0

Dies kann durch eine Kombination von Knoten des erreicht werden Pfad und URL :

  1. Benötigen Sie die Pakete:
const nodeUrl = require('url')
const nodePath = require('path')
  1. Erstellen Sie zunächst ein URL-Objekt, mit dem Sie arbeiten können:
> const myUrl = new nodeUrl.URL('https://example.com')
  1. Verwenden pathname=und path.joinkonstruieren Sie eine mögliche Kombination:
> myUrl.pathname = nodePath.join('/search', 'for', '/something/')
'/search/for/something/'

(Sie können sehen, wie liberal path.joinmit Argumenten ist)

  1. Zu diesem Zeitpunkt spiegelt Ihre URL das letztendlich gewünschte Ergebnis wider:
> myUrl.toString()
'https://example.com/search/for/something/'

Warum dieser Ansatz?

Diese Technik verwendet integrierte Bibliotheken. Je weniger Abhängigkeiten von Drittanbietern, desto besser, wenn es um CVEs, Wartung usw. geht.

PS: Manipuliere niemals URLs als Strings!

Wenn ich Code überprüfe, bin ich fest davon überzeugt , URLs niemals manuell als Zeichenfolgen zu bearbeiten . Schauen Sie sich zum einen an, wie kompliziert die Spezifikation ist .

Zweitens sollte das Fehlen / Vorhandensein eines abschließenden / vorangestellten Schrägstrichs ( /) nicht dazu führen, dass alles kaputt geht! Sie sollten niemals tun:

const url = `${baseUrl}/${somePath}`

und vor allem nicht:

uri: host + '/' + SAT_SERVICE + '/' + CONSTELLATION + '/',

Davon bin ich gerade in einer Codebasis begegnet.

Sean Patrick Murphy
quelle