Dapatkah saya menggunakan require ("path"). Join untuk menggabungkan url dengan aman?

128

Apakah ini aman digunakan require("path").joinuntuk menggabungkan URL, misalnya:

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

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

Jika tidak, cara apa yang Anda sarankan untuk melakukan ini tanpa menulis kode penuh jika?

Renato Gama
sumber
3
Lihat juga github.com/joyent/node/issues/2216
Kolonel Panic
5
Dalam kasus ada yang ingin menggunakan path.join, tetapi isu-isu menghindari pada Windows: 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 Masalahnya adalah jika Anda melakukan sesuatu seperti ini path.posix.join('http://localhost:9887/one/two/three/', '/four'), gabungan menghilangkan salah satu garis miring ganda dihttp://
Max Alexander
Ahh, ya - poin yang bagus. Dalam skenario tersebut, Anda ingin melakukan sesuatu seperti 'http://localhost:9887/one/two/three/'.replace(/^\/+|\/+$/, '') + '/' + '/four'.replace(/^\/+|\/+$/, '')dan Anda dapat melakukannya String.prototype.trimSlashes = function() { return this.replace(/^\/+|\/+$/, ''); }jika Anda tidak ingin mengetik ekspresi reguler berulang kali. stackoverflow.com/a/22387870/2537258
Timothy Zorn
atau['http://localhost:9887/one/two/three/', '/four'].map((part) => part. replace(/^\/+|\/+$/, '')).join('/')
Timothy Zorn

Jawaban:

142

Tidak. path.join()Akan mengembalikan nilai yang salah saat digunakan dengan URL.

Kedengarannya seperti yang Anda inginkan url.resolve. Dari dokumen Node :

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'

Sunting: Seperti yang ditunjukkan Andreas dengan benar dalam komentar, url.resolvehanya akan membantu jika masalahnya sesederhana contoh. url.parsejuga berlaku untuk pertanyaan ini karena ia mengembalikan bidang yang diformat secara konsisten dan dapat diprediksi melalui URLobjek yang mengurangi kebutuhan akan "kode penuh jika".

Matthew Bakaitis
sumber
1
Meskipun tidak persis seperti yang saya cari, ini juga memecahkan masalah saya. Terima kasih telah membantu!
Renato Gama
6
@AndreasHultgren komentar pertama benar. Jika contohnya url.resolve('/one/two/three/', 'four')maka outputnya adalah 'one/two/three/four'.
tavnab
3
Dalam kasus ada yang ingin menggunakan path.join, tetapi isu-isu menghindari pada Windows: 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
Komentarnya salah, url.resolve('/one/two/three', 'four') // '/one/two/four'jawabannya benar
Jonathan.
2
Perlu diketahui juga url.resolve()hanya butuh 2 argumen, sedangkan as path.join()butuh sembarang angka. Jadi tergantung pada apa yang Anda lakukan, Anda mungkin perlu melakukan panggilan bersarang, misalnya ..url.resolve(url.resolve(SERVER_URL, pagePath), queryString)
Molomby
47

Tidak, Anda tidak boleh menggunakan path.join()untuk menggabungkan elemen URL.

Ada paket untuk melakukan itu sekarang. Jadi, daripada menemukan kembali roda, tulis semua pengujian Anda sendiri, temukan bug, perbaiki, tulis lebih banyak pengujian, temukan casing edge yang tidak berfungsi, dll., Anda dapat menggunakan paket ini.

url-join

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

Install

npm install url-join

Pemakaian

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

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

console.log(fullUrl);

Cetakan:

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

batu
sumber
1
Ini. Ini fantastis. Terima kasih.
dudewad
6

Ketika saya mencoba PATH untuk menggabungkan bagian url saya mengalami masalah. PATH.joingaris '//' down to '/' dan cara ini membuat url absolut tidak valid (mis. http: // ... -> http: / ...). Bagi saya, perbaikan cepatnya adalah:

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

atau dengan solusi yang diposting oleh Kolonel Panic:

[pathA.replace(/^\/|\/$/g,""),pathB.replace(/^\/|\/$/g,"")].join("/")
Peter
sumber
Bagaimana jika saya mencoba membuat URL root-relative seperti ini /assets/foo:? Ini akan menghasilkan URL relatif-jalur-saat ini assets/foo.
Andrey Mikhaylov - lolmaus
5

Tidak! Di Windows path.joinakan bergabung dengan garis miring terbalik. URL HTTP selalu berupa garis miring ke depan.

Bagaimana tentang

> ["posts", "2013"].join("/")
'posts/2013'
Kolonel Panik
sumber
Ide bagus, tapi bagaimana jika argumen pertama sudah mendapat garis miring di akhir? mis .: ["posts/", "2013"].join("/")?
Renato Gama
1
@RenatoGama, posts//2013masih merupakan URL yang valid.
Goodwine
2
^ yang tidak akan berfungsi di semua domain, meskipun itu adalah URI yang valid.
BingeBoy
2
Secara khusus, Node's Express tidak mengabaikan garis miring asing untuk perutean.
Perseids
1
Dalam kasus ada yang ingin menggunakan path.join, tetapi isu-isu menghindari pada Windows: 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

Kami melakukannya seperti ini:

var _ = require('lodash');

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

Jika Anda menggunakan lodash , Anda dapat menggunakan oneliner sederhana ini:

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

terinspirasi oleh jawaban @Peter Dotchev

MK
sumber
3

Jika Anda menggunakan Angular, Anda dapat menggunakan Lokasi :

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

Bekerja hanya pada 2 argumen, jadi Anda harus melakukan panggilan berantai atau menulis fungsi pembantu untuk melakukannya jika diperlukan.

Qortex
sumber
2

Ini yang saya gunakan:

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

contoh:

url = joinUrlElements(config.mgmtServer, '/v1/o/', config.org, '/apps');
Cheeso
sumber
Bagaimana jika saya mencoba membuat URL root-relative seperti ini /assets/foo:? Ini akan menghasilkan URL relatif-jalur-saat ini assets/foo.
Andrey Mikhaylov - lolmaus
1
menambahkan garis miring? Maksud saya, ini pemeriksaan sederhana; Anda dapat menambahkannya sendiri.
Cheeso
4
Beginilah awalnya ... hal berikutnya yang Anda tahu bahwa Anda telah menghabiskan 8+ jam kumulatif untuk menemukan kasus edge yang tidak berfungsi dan memperbaikinya selama proyek Anda berlangsung.
batu
2

The WHATWG URL objek konstruktor memiliki (input, base)versi, dan inputbisa relatif menggunakan /, ./, ../. Gabungkan ini dengan path.posix.joindan Anda dapat melakukan apa saja:

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'
Pembuat kode
sumber
0

Solusi kustom typescript:

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
sumber
0

Solusi saya

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

Edit: jika Anda ingin mendukung lingkungan windows

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

Solusi kedua akan menggantikan semua garis miring terbalik, jadi bagian url seperti querystring dan hash juga dapat diubah, tetapi topiknya hanya bergabung dengan jalur url, jadi saya tidak menganggapnya sebagai masalah.

Killy
sumber
0

Ada jawaban kerja lainnya, tetapi saya pergi dengan yang berikut ini. Sebuah combo path.join / URL kecil.

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
sumber
0

Ini dapat dilakukan dengan kombinasi jalur Node dan URL :

  1. Membutuhkan paket:
const nodeUrl = require('url')
const nodePath = require('path')
  1. Mulailah dengan membuat objek URL untuk digunakan:
> const myUrl = new nodeUrl.URL('https://example.com')
  1. Gunakan pathname=dan path.joinuntuk membuat kombinasi yang mungkin:
> myUrl.pathname = nodePath.join('/search', 'for', '/something/')
'/search/for/something/'

(Anda dapat melihat betapa liberal path.joindengan argumen)

  1. Pada titik ini, URL Anda mencerminkan hasil akhir yang diinginkan:
> myUrl.toString()
'https://example.com/search/for/something/'

Mengapa pendekatan ini?

Teknik ini menggunakan pustaka bawaan. Semakin sedikit ketergantungan pihak ketiga semakin baik, dalam hal CVE, pemeliharaan, dll.

PS: Jangan pernah memanipulasi URL sebagai string!

Ketika saya meninjau kode, saya bersikeras tidak pernah memanipulasi URL sebagai string secara manual . Pertama, lihat betapa rumitnya speknya .

Kedua, tidak adanya / adanya garis miring ( /) di belakang / diawali tidak akan menyebabkan semuanya rusak! Anda tidak boleh melakukan:

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

dan terutama tidak:

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

Yang baru saja saya temui di basis kode.

Sean Patrick Murphy
sumber