require ( "path"). join을 사용하여 URL을 안전하게 연결할 수 있습니까?


128

다음과 같이 require("path").joinURL을 연결하는 데 사용 하는 것이 안전합니까?

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

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

그렇지 않다면 ifs로 가득 찬 코드를 작성하지 않고이 작업을 수행하는 방법은 무엇입니까?



5
경우 사람이 Windows에서 path.join하지만, 피할 문제를 사용하고자하는 : 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
디모데 죤

5
문제는이 같은 일을 할 경우 즉 @TimothyZorn path.posix.join('http://localhost:9887/one/two/three/', '/four')의 가입에 이중 슬래시 중 하나를 제거를 얻을http://
최대 알렉산더

아, 예-좋은 지적입니다. 이러한 시나리오에서는 다음과 같은 작업 을 수행하고 정규 표현식을 반복해서 입력하고 싶지 않은 경우 수행 'http://localhost:9887/one/two/three/'.replace(/^\/+|\/+$/, '') + '/' + '/four'.replace(/^\/+|\/+$/, '')String.prototype.trimSlashes = function() { return this.replace(/^\/+|\/+$/, ''); } 있습니다. stackoverflow.com/a/22387870/2537258
Timothy Zorn

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

답변:


142

아니. path.join() . URL과 함께 사용하면 잘못된 값을 반환합니다.

당신이 원하는 것 같은데 url.resolve. 로부터 노드 문서 :

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'

편집 : Andreas가 의견에서 올바르게 지적했듯이 url.resolve문제가 예제처럼 간단한 경우에만 도움이됩니다. url.parse또한 URL"ifs로 가득 찬 코드"에 대한 필요성을 줄이는 객체를 통해 일관되고 예측 가능한 형식의 필드를 반환하기 때문에이 질문에도 적용됩니다 .


1
내가 찾던 것이 정확히는 아니지만 내 문제도 해결됩니다. 도움을 주셔서 감사합니다!
Renato Gama 2013 년

6
@AndreasHultgren 첫 번째 의견이 정확합니다. 예제가 있다면 url.resolve('/one/two/three/', 'four')출력은 'one/two/three/four'.
tavnab

3
경우 사람이 Windows에서 path.join하지만, 피할 문제를 사용하고자하는 : 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
디모데 죤

2
url.resolve('/one/two/three', 'four') // '/one/two/four'답변이 정확 하지 않습니다
Jonathan.

2
또한 url.resolve()as path.join()는 임의의 숫자를 취하는 2 개의 인수 만 사용합니다 . 따라서 수행중인 작업에 따라 호출을 중첩해야 할 수 있습니다. 예를 들어 ..url.resolve(url.resolve(SERVER_URL, pagePath), queryString)
Molomby

47

아니요, path.join()URL 요소를 결합 하는 데 사용해서는 안됩니다 .

지금 그렇게하기위한 패키지가 있습니다. 따라서 바퀴를 재발 명하고, 모든 테스트를 작성하고, 버그를 찾고, 수정하고, 더 많은 테스트를 작성하고, 작동하지 않는 엣지 케이스를 찾는 등이 패키지를 사용할 수 있습니다.

URL 조인

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

설치

npm install url-join

용법

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

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

console.log(fullUrl);

인쇄물:

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


1
이. 환상적이다. 감사합니다.
dudewad 2011


6

URL 부분을 연결하기 위해 PATH를 시도했을 때 문제가 발생합니다. PATH.join'//'를 '/'로 줄이면 절대 URL이 무효화됩니다 (예 : http : // ...-> http : / ...). 나에게 빠른 수정은 다음과 같습니다.

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

또는 패닉 대령이 게시 한 솔루션 :

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

다음과 같은 루트 상대 URL을 만들려고하면 /assets/foo어떻게됩니까? 현재 경로 상대 URL이 assets/foo됩니다.
Andrey Mikhaylov-lolmaus

5

아니! Windows path.join에서는 백 슬래시로 결합됩니다. HTTP URL은 항상 슬래시입니다.

어때

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

좋은 생각이지만 첫 번째 인수의 끝에 이미 슬래시가있는 경우 어떻게해야합니까? 예 : ["posts/", "2013"].join("/")?
Renato Gama 2013

1
@RenatoGama posts//2013는 여전히 유효한 URL입니다.
Goodwine 2013

2
^ 유효한 URI이지만 모든 도메인에서 작동하지 않습니다.
BingeBoy 2015

2
특히 Node의 Express는 라우팅을 위해 불필요한 슬래시를 무시하지 않습니다.
Perseids

1
경우 사람이 Windows에서 path.join하지만, 피할 문제를 사용하고자하는 : 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
디모데 죤

5

우리는 다음과 같이합니다.

var _ = require('lodash');

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

4

lodash를 사용하는 경우 다음과 같은 간단한 oneliner를 사용할 수 있습니다.

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

@Peter Dotchev의 답변에서 영감을 얻었습니다.


3

이것이 내가 사용하는 것입니다.

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

예:

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

다음과 같은 루트 상대 URL을 만들려고하면 /assets/foo어떻게됩니까? 현재 경로 상대 URL이 assets/foo됩니다.
Andrey Mikhaylov-lolmaus

1
슬래시를 추가 하시겠습니까? 내 말은, 간단한 수표입니다. 직접 추가 할 수 있습니다.
Cheeso 2015 년

3
이것이 시작되는 방법입니다. 다음으로 8 시간 이상을 누적하여 작동하지 않는 케이스를 찾아서 프로젝트 과정에서 수정했습니다.
stone

3

Angular를 사용하는 경우 Location 을 사용할 수 있습니다 .

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

하지만 2 개의 인수에서만 작동하므로 필요한 경우 호출을 연결하거나 도우미 함수를 작성해야합니다.


2

WHATWG URL 객체의 생성자가이 (input, base)버전과는 input사용하여 상대 할 수있다 /, ./, ../. 이것을 결합하면 path.posix.join무엇이든 할 수 있습니다.

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 사용자 지정 솔루션 :

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

내 솔루션

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

편집 : Windows 환경을 지원하려는 경우

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

두 번째 솔루션은 모든 백 슬래시를 대체하므로 쿼리 문자열 및 해시와 같은 URL 부분도 변경 될 수 있지만 주제는 URL 경로에만 결합되므로 문제로 간주하지 않습니다.


0

다른 작업 답변이 있지만 다음과 같이 갔다. 약간의 path.join / 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

0

이것은 Node의 경로URL을 조합하여 수행 할 수 있습니다 .

  1. 패키지 필요 :
const nodeUrl = require('url')
const nodePath = require('path')
  1. 작업 할 URL 개체를 만들어 시작합니다.
> const myUrl = new nodeUrl.URL('https://example.com')
  1. 및를 사용 pathname=하여 path.join가능한 조합을 구성하십시오.
> myUrl.pathname = nodePath.join('/search', 'for', '/something/')
'/search/for/something/'

(당신은 path.join논쟁이 얼마나 자유주의 인지 알 수 있습니다 )

  1. 이 시점에서 URL은 원하는 궁극적 인 결과를 반영합니다.
> myUrl.toString()
'https://example.com/search/for/something/'

왜 이런 접근 방식입니까?

이 기술은 내장 라이브러리를 사용합니다. CVE, 유지 관리 등에 관해서는 타사 종속성이 적을수록 좋습니다.

PS : URL을 문자열로 조작하지 마십시오!

코드를 검토 할 때 URL을 문자열로 수동으로 조작하지 않는 것에 대해 단호 합니다 . 하나 는 사양이 얼마나 복잡한 지보세요 .

둘째, 후행 / 접두사 슬래시 ( /) 의 부재 / 존재로 인해 모든 것이 중단되어서는 안됩니다! 절대로 다음을 수행해서는 안됩니다.

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

특히 그렇지 않습니다.

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

그 중 방금 코드베이스에서 만났습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.