Required ("path"). Join URL'leri güvenli bir şekilde birleştirmek için kullanabilir miyim?


128

Bu require("path").join, URL'leri birleştirmek için güvenli midir, örneğin:

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

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

Değilse, ifs kodlarıyla dolu kod yazmadan bunu yapmak için hangi yolu önerirsiniz?



5
Durumda herkes Windows üzerinde path.join ama önlemek sorunlarını kullanmak isteyen: 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 Sorun şu ki, böyle bir şey yaparsanız path.posix.join('http://localhost:9887/one/two/three/', '/four'), birleştirme çift eğik çizgilerden birinden kurtulurhttp://
Max Alexander

Ahh, evet - iyi nokta. Bu senaryolarda, böyle bir şey yapmak ister 'http://localhost:9887/one/two/three/'.replace(/^\/+|\/+$/, '') + '/' + '/four'.replace(/^\/+|\/+$/, '')ve siz olabilir yapmak String.prototype.trimSlashes = function() { return this.replace(/^\/+|\/+$/, ''); }size tekrar tekrar normal ifadeyi yazın istemiyorsanız. stackoverflow.com/a/22387870/2537258
Timothy Zorn

veya['http://localhost:9887/one/two/three/', '/four'].map((part) => part. replace(/^\/+|\/+$/, '')).join('/')
Timothy Zorn

Yanıtlar:


142

Hayır. path.join() . URL'lerle kullanıldığında yanlış değerler döndürür.

İstediğin gibi geliyor url.resolve. Gönderen Düğüm docs :

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'

Düzenleme: Andreas'ın bir yorumda doğru bir şekilde işaret ettiği gibi, url.resolveyalnızca sorun örnek kadar basitse yardımcı olur. url.parseBu soru için de geçerlidir çünkü URLnesne aracılığıyla tutarlı ve tahmin edilebilir şekilde biçimlendirilmiş alanlar döndürür ve "ifs ile dolu kod" ihtiyacını azaltır.


1
Tam olarak aradığım şey olmasa da bu da sorunumu çözüyor. Yardım için teşekkürler!
Renato Gama

6
@AndreasHultgren ilk yorum doğru. Örnek url.resolve('/one/two/three/', 'four')olsaydı, çıktı olurdu 'one/two/three/four'.
tavnab

3
Durumda herkes Windows üzerinde path.join ama önlemek sorunlarını kullanmak isteyen: 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
Yorumlar yanlış, url.resolve('/one/two/three', 'four') // '/one/two/four'cevap doğru
Jonathan.

2
Ayrıca , herhangi bir sayının alındığı url.resolve()yerde yalnızca 2 argüman path.join()aldığını unutmayın. Dolayısıyla, ne yaptığınıza bağlı olarak aramaları iç içe url.resolve(url.resolve(SERVER_URL, pagePath), queryString)
geçirmeniz

47

Hayır, kullanmamalısın path.join() URL öğelerini birleştirmek için .

Şimdi bunu yapmak için bir paket var. Tekerleği yeniden icat etmek, kendi testlerinizi yazmak, hataları bulmak, düzeltmek, daha fazla test yazmak, çalışmadığı bir uç durum bulmak vb. Yerine bu paketi kullanabilirsiniz.

url-join

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

Yüklemek

npm install url-join

kullanım

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

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

console.log(fullUrl);

Baskılar:

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


1
Bu. Bu fantastik. Teşekkür ederim.
dudewad


6

URL parçalarını birleştirmek için PATH'i denediğimde sorunlarla karşılaşıyorum. PATH.join'//' '/' aşağı '/' çizgileri oluşturur ve bu şekilde mutlak bir url'yi geçersiz kılar (örn. http: // ... -> http: / ...). Benim için hızlı bir düzeltme şuydu:

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

veya Albay Panic tarafından yayınlanan çözümle:

[pathA.replace(/^\/|\/$/g,""),pathB.replace(/^\/|\/$/g,"")].join("/")

Ben böyle bir köke ilişkin URL'yi oluşturmaya çalışıyorum ne: /assets/foo? Geçerli yola göre URL ile sonuçlanacaktır assets/foo.
Andrey Mikhaylov - lolmaus

5

Hayır! Windows'ta path.jointers eğik çizgi ile katılacak. HTTP url'leri her zaman eğik çizgilerdir.

Ne dersin

> ["posts", "2013"].join("/")
'posts/2013'

İyi fikir, ama ya ilk argümanın sonunda zaten bir eğik çizgi varsa? ör .: ["posts/", "2013"].join("/")?
Renato Gama

1
@RenatoGama, posts//2013hala geçerli bir URL'dir.
Goodwine

2
^ geçerli bir URI olsa bile tüm etki alanlarında çalışmaz.
BingeBoy

2
Özellikle, Node's Express yönlendirme için gereksiz eğik çizgileri göz ardı etmez.
Perseids

1
Durumda herkes Windows üzerinde path.join ama önlemek sorunlarını kullanmak isteyen: 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

Bunu şöyle yapıyoruz:

var _ = require('lodash');

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

3

Lodash kullanıyorsanız , bu basit oneliner'ı kullanabilirsiniz:

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

esinlenerek @Peter Dotchev en cevabı


3

Eğer açısal kullanırsanız, kullanabilirsiniz Konum :

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

Yine de sadece 2 bağımsız değişken üzerinde çalışır, bu nedenle gerekirse bunu yapmak için aramaları zincirlemeniz veya bir yardımcı işlev yazmanız gerekir.


2

Kullandığım şey bu:

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

misal:

url = joinUrlElements(config.mgmtServer, '/v1/o/', config.org, '/apps');

Ben böyle bir köke ilişkin URL'yi oluşturmaya çalışıyorum ne: /assets/foo? Geçerli yola göre URL ile sonuçlanacaktır assets/foo.
Andrey Mikhaylov - lolmaus

1
eğik çizginin başına mı? Demek istediğim, bu basit bir çek; kendiniz ekleyebilirsiniz.
Cheeso

4
İşte böyle başlıyor ... Bundan sonra, 8 saatin üzerinde birikerek çalışmayan uç vakaları bulup projeniz boyunca bunları düzeltmek için harcadığınızı biliyorsunuz.
taş

2

WHATWG URL nesne yapıcı bir sahiptir (input, base)sürümü ve inputkullanan göreceli olabilir /, ./, ../. Bunu ile birleştirin path.posix.joinve her şeyi yapabilirsiniz:

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'

0

Typescript özel çözümü:

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');

0

Çözümüm

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

Düzenle: Windows ortamlarını desteklemek istiyorsanız

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

İkinci çözüm tüm ters eğik çizgilerin yerini alacak, bu nedenle sorgu dizesi ve karma gibi url parçaları da değiştirilebilir, ancak konu yalnızca url yoluna katılıyor, bu yüzden bunu bir sorun olarak görmüyorum.


0

Başka çalışan cevaplar da var, ancak aşağıdakileri yaptım. Küçük bir path.join / URL combo.

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

0

Bu, Düğümün yolu ve URL'sinin bir kombinasyonu ile gerçekleştirilebilir :

  1. Paketleri gerektir:
const nodeUrl = require('url')
const nodePath = require('path')
  1. Çalışmak için bir URL nesnesi oluşturarak başlayın:
> const myUrl = new nodeUrl.URL('https://example.com')
  1. Olası herhangi bir kombinasyonu oluşturmak için pathname=ve kullanın path.join:
> myUrl.pathname = nodePath.join('/search', 'for', '/something/')
'/search/for/something/'

( path.joinargümanlarda ne kadar liberal olduğunu görebilirsiniz )

  1. Bu noktada, URL'niz istenen nihai sonucu yansıtır:
> myUrl.toString()
'https://example.com/search/for/something/'

Neden bu yaklaşım?

Bu teknik yerleşik kitaplıkları kullanır. CVE'ler, bakım vb. Söz konusu olduğunda, üçüncü taraf bağımlılıkları ne kadar az olursa o kadar iyidir.

Not: URL'leri asla dizeler olarak kullanmayın!

Kodu incelerken, URL'leri asla manuel olarak dize olarak değiştirmeme konusunda kararlıyım . Birincisi, şartnamenin ne kadar karmaşık olduğuna bakın .

İkinci olarak, sondaki / önekli eğik çizginin ( /) yokluğu / varlığı, her şeyin bozulmasına neden olmamalıdır! Asla yapmamalısın:

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

ve özellikle de değil:

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

Bir kod tabanında az önce karşılaştığım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.