

现代 JavaScript 中更安全的 URL 读写
source link: https://blog.p2hp.com/archives/10257
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

您可能在不知不觉中以不安全的方式编写 URL
你能发现这段代码中的错误吗?
const url = `https://builder.io/api/v2/content
?model=${model}&locale=${locale}?query.text=${text}`
const res = await fetch(url)
至少有三个!
我们将在下面分解它们:
常见问题 #1:不正确的分隔符

哎呀!这当然是一个新手错误,但很容易错过,即使经过 10 年的 JS 开发,我也在我自己的代码中发现了这个错误。
根据我的经验,一个常见的罪魁祸首是在编辑或移动代码之后。例如,您有一个结构正确的 URL,然后将一个片段从一个片段复制到另一个片段,然后错过了参数分隔符的错误排序。
连接时也会发生这种情况。例如:
url = url '?foo=bar'
但是等等,原来的url
可能有一个查询参数。好的,所以这应该是:
url = url '&foo=bar'
但是等等,如果原来url
没有查询参数那么现在这是错误的。啊。
常见问题 #2:忘记编码

啊。model
并且locale
可能不需要编码,因为它们是 URL 安全值,但我并没有停下来思考text
可以是所有类型的文本,包括空格和特殊字符,这会给我们带来问题。
因此,也许我们会矫枉过正,让事情变得更加安全:
const url = `https://builder.io/api/v2/content
?model=${
encodeURIComponent(model)
}&locale=${
encodeURIComponent(locale)
}&query.text=${
encodeURIComponent(text)
}`
但事情感觉有点......丑陋。
常见问题 #3:意外的空白字符

钱币。为了将这个长 URL 分成多行,我们不小心在 URL 中包含了换行符和额外的空格,这将导致无法按预期进行抓取。
我们现在可以正确地分解字符串,但我们变得更加混乱和难以阅读:
const url = `https://builder.io/api/v2/content`
`?model=${
encodeURIComponent(model)
}&locale=${
encodeURIComponent(locale)
}&query.text=${
encodeURIComponent(text)
}`
仅仅为了使构建一个 URL 正确就需要很多。下一次我们是否会记住这一切,尤其是在截止日期即将到来且我们需要尽快发布新功能或修复时?
一定有更好的方法。

URL
营救的构造函数
解决上述挑战的更清洁、更安全的解决方案是使用URL 构造函数:
const url = new URL('https://builder.io/api/v2/content')
url.searchParams.set('model', model)
url.searchParams.set('locale', locale)
url.searchParams.set('text', text)
const res = await fetch(url.toString())
这为我们解决了几件事:
- 分隔符总是正确的(
?
对于第一个参数,以及之后的参数)。 - 所有参数都自动编码。
- 为长 URL 跨多行时没有额外空白字符的风险。
对于我们正在修改 URL 但不知道当前状态的情况,它也非常有用。
例如,而不是有这个问题:
url = (url.includes('?') ? '&' : '?') 'foo=bar'
我们可以改为:
// Assuming `url` is a URL
url.searchParams.set('foo', 'bar')
// Or if URL is a string
const structuredUrl = new URL(url)
structuredUrl.searchParams.set('foo', 'bar')
url = structuredUrl.toString()
同样,你也可以写URL的其他部分:
const url = new URL('https://builder.io')
url.pathname = '/blog' // Update the path
url.hash = '#featured' // Update the hash
url.host = 'www.builder.io' // Update the host
url.toString() // https://www.builder.io/blog#featured
读取 URL 值
现在,“我只想在没有库的情况下从当前 URL 读取查询参数”这个由来已久的问题得到了解决。
const pageParam = new URL(location.href).searchParams.get('page')
或者例如更新当前 URL:
const url = new URL(location.href)
const currentPage = Number(url.searchParams.get('page'))
url.searchParams.set('page', String(currentPage 1))
location.href = url.toString()
但这不仅限于浏览器。它也可以在 Node.js 中使用
const http = require('node:http');
const server = http.createServer((req, res) => {
const url = new URL(req.url, `https://${req.headers.host}`)
// Read path, query, etc...
});
以及 Deno:
import { serve } from "https://deno.land/std/http/mod.ts";
async function reqHandler(req: Request) {
const url = new URL(req.url)
// Read path, query, etc...
return new Response();
}
serve(reqHandler, { port: 8000 });
要知道的 URL 属性
URL 实例支持您已经在浏览器中使用的所有属性,例如 onwindow.location
或 anchor 元素,所有这些您都可以读写:
const url = new URL('https://builder.io/blog?page=1');
url.protocol // https:
url.host // builder.io
url.pathname // /blog
url.search // ?page=1
url.href // https://builder.io/blog?page=1
url.origin // https://builder.io
url.searchParams.get('page') // 1
或者,一目了然:

URLSearchParams方法要知道
该URLSearchParams
对象可在URL
实例上访问,url.searchParams
支持许多方便的方法:
searchParams.has(name)
检查搜索参数是否包含给定名称:
url.searchParams.has('page') // true
searchParams.get(name)
获取给定参数的值:
url.searchParams.get('page') // '1'
searchParams.getAll(name)
获取为参数提供的所有值。如果您允许同名的多个值,这很方便,例如&page=1&page=2
:
url.searchParams.getAll('page') // ['1']
searchParams.set(name, value)
设置参数的值:
url.searchParams.set('page', '1')
searchParams.append(name, value)
附加一个参数——如果你可能多次支持同一个参数,这很有用,比如&page=1&page=2
:
url.searchParams.append('page', '2')
searchParams.delete(name)
从 URL 中完全删除一个参数:
url.searchParams.delete('page')
要知道的一大陷阱是传递给 URL 构造函数的所有 URL 都必须是绝对的。
例如,这将引发错误:
new URL('/blog') // ERROR!
您可以通过提供原点作为第二个参数来解决这个问题,如下所示:
new URL('/blog', 'https://builder.io')
或者,如果您真的只需要使用 URL 部分, 如果您只需要使用相对 URL 的查询参数,则可以直接使用URLSearchParams :
const params = new URLSearchParams('page=1')
params.set('page=2')
params.toString()
URLSearchParams
还有一个优点,那就是它也可以将键值对的对象作为其输入:
const params = new URLSearchParams({
page: 1,
text: 'foobar',
})
params.set('page=2')
params.toString()
浏览器和运行时支持
new URL
支持所有现代浏览器,以及 Node.js 和 Deno!(来源)

使用您的组件进行可视化构建
Builder.io是一个无头 CMS,可让您直接 在现有站点中拖放 组件。
// Dynamically render your components
export function MyPage({ json }) {
return
}
registerComponents([MyHero, MyProducts])
Recommend
-
91
.NET/.NET Core中更清晰的堆栈跟踪
-
5
在 Android O 中更安全地获取应用 – Android开发中文站你的位置:Android开发中文站 > Android开发 >
-
7
23 岁的 QQ,比你想象中更好用 对现在的科技媒体来说,腾讯 QQ 的存在就好比是远方的异邦,古代西方眼中的东方:它总是笼罩着神秘感,只有在某次重大更新时才会吸引一些眼球,然后又重新归于未知。
-
6
tomoon | 探究量化系统中更合理的数据架构传递方式 | 犀牛的博客 犀牛的博客
-
5
← 今日好价 1115日常用品中发现的化学物质激活了子宫肌瘤的生长 →
-
5
V2EX › 问与答 探索编程中更有趣的方向 RuLaiFo ·...
-
5
2023-05-16 09:05 AMD 副总裁:公司正考虑在 Ryzen 处理器产品线中更深入集成 AI 据 PC World 报道,AMD 副总裁 David McAfee 日前受访时表示,AMD 在 CPU 中引入了特殊的推理处理单元(IPU)模块,专门处理和人工智能相关的负载任...
-
7
1 个月前 Spring6 ...
-
4
大家好,我是爱读书的master-john新家搬家,家里的二层小楼面积非常大不说,就连床也是那种腾空的,常规的清洁工具真的很难满足日常清洁的需要,稍微长一点的床底下就成了卫生死角。
-
8
新势力倒闭,车机变无用板砖,新势力倒闭比想象中更麻烦 紧邻着广州珠江新城中轴线,花城广场的东侧,有一家恒驰展示体...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK