我可以使用require(“ path”)。join安全地连接网址吗?


128

使用这种方法可以安全地require("path").join连接URL,例如:

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
如果你想使用path.join,但要避免问题在Windows上:path.posix.join('/one/two/three', 'four') // '/one/two/three/fourpath.posix.join('/one/two/three/', 'four') // '/one/two/three/fourpath.posix.join('/one/two/three/', '/four') // '/one/two/three/four
蒂莫西·佐恩

5
@TimothyZorn问题是,如果您执行这样的操作,则联接将path.posix.join('http://localhost:9887/one/two/three/', '/four')摆脱双斜线之一http://
Max Alexander

嗯-是的。在这些情况下,你会想要做这样的事情'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

Answers:


141

path.join()与网址一起使用时,编号 将返回不正确的值。

听起来像你想要的url.resolve。从Node 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'

编辑: 正如安德里亚斯(Andreas)在评论中正确指出的那样,url.resolve仅当问题与示例一样简单时,它才会有所帮助。 url.parse这也适用于此问题,因为它通过URL对象返回了一致且可预测的格式化字段,从而减少了对“ ifs满的代码”的需求。


1
尽管不是我一直在寻找的东西也可以解决我的问题。感谢您的帮助!
Renato Gama

6
@AndreasHultgren第一条评论是正确的。如果是该示例,url.resolve('/one/two/three/', 'four')则输出为'one/two/three/four'
tavnab

3
如果你想使用path.join,但要避免问题在Windows上:path.posix.join('/one/two/three', 'four') // '/one/two/three/fourpath.posix.join('/one/two/three/', 'four') // '/one/two/three/fourpath.posix.join('/one/two/three/', '/four') // '/one/two/three/four
蒂莫西·佐恩

2
评论不正确,url.resolve('/one/two/three', 'four') // '/one/two/four'答案是正确的
乔纳森。

2
另请注意,url.resolve()仅接受2个参数,其中as path.join()接受任何数字。因此,根据您的工作,您可能需要嵌套呼叫,例如url.resolve(url.resolve(SERVER_URL, pagePath), queryString)
。– Molomby

47

不,您不应该path.join()用来连接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


6

当我尝试使用PATH链接URL部分时,我遇到了问题。 PATH.join将'//'条带化为'/',这样会使绝对网址无效(例如http:// ...-> http:/ ...)。对我来说,快速解决方法是:

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

或使用Panic上校发布的解决方案:

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

如果我要建立像这样的根目录相对URL,该/assets/foo怎么办?它将导致相对于current-path的URL assets/foo
安德烈·米哈伊洛夫

5

没有!在Windows path.join上将加反斜杠。HTTP url总是正斜杠。

怎么样

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

好主意,但是如果第一个参数末尾已经有一个斜杠怎么办?例如:["posts/", "2013"].join("/")
Renato Gama

1
@RenatoGama,posts//2013仍然是有效的网址。
2013年

2
即使它是有效的URI,它也不适用于所有域。
BingeBoy 2015年

2
具体来说,Node Express不会忽略用于路由的多余斜杠。
英仙座

1
如果你想使用path.join,但要避免问题在Windows上:path.posix.join('/one/two/three', 'four') // '/one/two/three/fourpath.posix.join('/one/two/three/', 'four') // '/one/two/three/fourpath.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怎么办?它将导致相对于current-path的URL assets/foo
安德烈·米哈伊洛夫

1
放在斜线前?我的意思是,这很简单。您可以自己添加。
Cheeso 2015年

3
这就是它的开始...接下来的一件事,您知道您已经花费了8个小时以上的时间来查找不起作用的边缘案例,并在项目过程中对其进行修复。

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

打字稿自定义解决方案:

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部分(例如querystring和hash)也可能会被更改,但是本主题仅加入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 + '/',

我只是在代码库中遇到的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.