我可以使用 request (“ path”) . join 来安全地连接 url 吗?

使用 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'

如果没有,您建议用什么方法来做到这一点,而不用编写充满 If 的代码?

92945 次浏览

不! 在 Windowspath.join中将使用反斜杠连接。 HTTP URL 总是使用正斜杠。

怎么样

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

当与 URL 一起使用时,path.join()将返回不正确的值。

听起来你想要 new URL():

new URL('/one', 'http://example.com/').href    // 'http://example.com/one'
new URL('/two', 'http://example.com/one').href // 'http://example.com/two'

请注意,url.resolve现在在 节点文档中被标记为不推荐使用。

正如 Andreas 在评论中正确指出的那样,url.resolve(也是 不赞成)只有在问题和示例一样简单的情况下才会有所帮助。url.parse也适用于这个问题,因为它通过 URL对象返回一致且可预测的格式化字段,这减少了对“充满 if 的代码”的需求。然而,new URL()也是 url.parse的替代品。

当我尝试 PATH 连接 URL 部分时,我遇到了问题。 从 PATH.join条纹“//”到“/”,这样会使绝对 url 无效(例如 http://...-> http:/...)。 对我来说,一个快速的解决办法是:

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

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

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

我用的是这个:

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

我们这样做:

var _ = require('lodash');


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

不,您不应该使用 path.join()来连接 URL 元素。

现在有一个这样做的包裹。因此,与其重新发明轮子,编写所有自己的测试,找到 bug,修复它们,编写更多的测试,找到它不能工作的边缘情况,等等,您可以使用这个包。

Url-join

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

如果你正在使用 浪荡,你可以使用这个简单的线条:

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

受到 @ Peter Dotchev’s答案的启发

Axios 有一个可以组合 URL 的 helper 函数。

function combineURLs(baseURL, relativeURL) {
return relativeURL
? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
: baseURL;
}

来源: Https://github.com/axios/axios/blob/fe7d09bb08fa1c0e414956b7fc760c80459b0a43/lib/helpers/combineurls.js

如果你使用角度,你可以使用 位置:

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

但是只能在2个参数上工作,所以如果需要的话,您必须链接调用或编写一个 helper 函数来完成这项工作。

自定义解决方案:

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

对象构造函数有一个 (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'

我的解决办法

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

编辑: 如果要支持 Windows 环境

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

第二个解决方案将替换所有的反斜杠,因此像 querystring 和 hash 这样的 url 部分也可能被修改,但是主题只是连接 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

这可以通过结合 Node 的 路径网址来实现:

  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. 在这一点上,你的网址反映了最终的期望结果:
> myUrl.toString()
'https://example.com/search/for/something/'

为什么这么做?

这种技术使用内置的库。当涉及到 CVE、维护等时,第三方依赖性越少越好。

没有什么比标准的 libs 更能被证明或更好的测试了。

附注: 永远不要将 URL 作为字符串操作!

当我回顾代码的时候,我坚持使用 从不手动操作 URL 作为字符串

其次,没有/出现后缀/前缀斜杠(/)不应该导致所有东西都断掉! 你永远不应该这样做:

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

特别是:

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

我见过。

到张贴这个答案的时候,url.resolve()是不推荐的;

我在 Nodejs 加入了 path:

const path = require('path');
const url = require('url');




let myUrl = new URL('http://ignore.com');
myUrl.pathname=path.join(firstpath, secondpath);
console.log(myUrl.pathname)

这种方法记录正确的 URL 路径,并且对我的情况有效。

你对这种方法有什么看法?

谢谢

内置路径和 URL 库的组合提供了最佳解决方案。

然而,上面的答案不能处理相对 url (即:”)的情况。./foo”)添加到现有 URL (即: “ http://example.com/test/bar" ;)。简单地执行 new URL("../foo","http://example.com/test/bar").href会产生“ http://example.com/foo"”,(对我来说)错误地丢弃了原始路径的其余部分。

一个简单的解决办法是:

var base = "http://example.com:8080/foo/bar";
var rel = "../test";
var resolved = new URL( path.resolve(new URL(base).pathname, rel ), base ).href;
// Result: http://example.com:8080/foo/test

注意: 如果您关心 URL Search Params (在这个场景中似乎不太可能) ,那么您应该将上面的每个片段保存为离散变量,并在获得 href 输出之前设置新的 url.searchParams = oldUrl.searchParams