@ensdomains/ens-avatar

中文文档
1.0.6发布于 2026/10/01MITTypeScriptESM + CJS近 30 天下载 2566

用于节点和浏览器的Avatar解析器库.

中文使用文档
文档目录25 节
  1. 重要说明
  2. 平台支持
  3. 开始
  4. 先决条件
  5. 安装
  6. 使用量
  7. 支持的外观规格
  8. 无
  9. URIs 参考文献
  10. 选项
  11. 缓存 (默认: 已禁用)
  12. 自定义IPFS网关 (默认 : https://ipfs.io (英语) (中文(简体) )
  13. 自定义线网关 (默认 : https://arweave.net (中文(简体) ) (中文(简体) )
  14. 市场 Api 键 (过失: )
  15. URL 拒绝列表 (过失:[])
  16. 限制 (故障: 3000 ms, 1 MiB, 5个方向调整, 256 KiB SVG)
  17. 自定义代理( 只有节点 )
  18. 允许私人IP (错误:虚假) - 说吧 仅限开发
  19. 云花岗工人
  20. 警卫
  21. SS 保护
  22. SSRF 保护
  23. 看守阅读的CCIP
  24. 服役的阿凡达人
  25. 演示

语录

用于Node.js,浏览器和边缘运行时间(Cloudflare Workers等)的Avatar解析器库.

重要说明

  • 带上你的连锁客户端. AvatarResolver 使用一个 ChainClient 而不是一个原始供应商, 所以核心船与 捆绑中没有醚。用一行适配器来包装您的 SDK :
    • 醚: import { fromEthers } from '@ensdomains/ens-avatar/ethers' → new AvatarResolver(fromEthers(provider))
    • 维姆: import { fromViem } from '@ensdomains/ens-avatar/viem' → new AvatarResolver(fromViem(client))
    • ethers 财务报告和审定财务报表 viem 为: 可选同伴依赖关系 ——只安装您使用的一款.
  • 1.0.4 + 版本 (中文) 使用本地获取 API 实现最大兼容性跨平台,包括 Cloudflare Workers 和其他边缘运行时间.
  • 名称分辨率使用 ENS 通用解析器,因此脱链(出道/L2)和ENSIP-10通卡名称解析出框. 醚适配器在一次CCIP-read-aware呼叫中获取所有者地址和avatar/header记录(再加一次,只分类为模棱两可的失败);viem适配器使用viem的 getEnsText 财务报告和审定财务报表 getEnsAddress (两通来电. 通过适配器推翻合同 universalResolverAddress 选项.
  • NFT变相器必须位于客户的链上. 两个适配器都报告其链式ID和 eip155:<chainId>/… 另一条链子上的活字 ChainMismatch 而不是被从错误的链子读取。 习惯 ChainClient 选择通过执行 getChainId()。 。 。 .

平台支持

这个图书馆无缝地跨越:

  • ✅ 节点.js 22+( 使用本地取取或 http 适配器)
  • ✅ 浏览器 (所有现代浏览器)
  • ✅ 云花岗工人
  • ✅ 其他边缘运行时间 支持标准获取 API

开始

先决条件

  • 准备一个乙醚v6供应商或viem公共客户端.

好样的! SVG sanitization在浏览器,Node.js, 和边缘运行时间(Cloudflare Workers)——不需要DOM多填充(jsdom).

安装

# npm
npm i @ensdomains/ens-avatar
# pnpm
pnpm add @ensdomains/ens-avatar
# yarn
yarn add @ensdomains/ens-avatar

使用量

有乙醚的:

import { JsonRpcProvider } from 'ethers';
import { AvatarResolver, utils as avtUtils } from '@ensdomains/ens-avatar';
import { fromEthers } from '@ensdomains/ens-avatar/ethers';

const provider = new JsonRpcProvider(/* ... */);
const resolver = new AvatarResolver(fromEthers(provider));

async function getAvatar() {
    const avatarURI = await resolver.getAvatar('tanrikulu.eth');
    // avatarURI = https://ipfs.io/ipfs/QmUShgfoZQSHK3TQyuTfUpsc8UfeNfD8KwPUvDBUdZ4nmR
}

async function getHeader() {
    const headerURI = await resolver.getHeader('tanrikulu.eth');
    // headerURI = https://ipfs.io/ipfs/QmRFnn6c9rj6NuHenFVyKXb6tuKxynAvGiw7yszQJ2EsjN
}

async function getAvatarMetadata() {
    const avatarMetadata = await resolver.getMetadata('tanrikulu.eth');
    // avatarMetadata = { image: ... , uri: ... , name: ... , description: ... }
    const headerMetadata = await resolver.getMetadata('tanrikulu.eth', 'header');
    // headerMetadata = { image: ... , uri: ... , name: ... , description: ... }
    const avatarURI = avtUtils.getImageURI({ metadata: avatarMetadata });
    // avatarURI = https://ipfs.io/ipfs/QmUShgfoZQSHK3TQyuTfUpsc8UfeNfD8KwPUvDBUdZ4nmR
}

与Viem: (英语)

import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
import { AvatarResolver } from '@ensdomains/ens-avatar';
import { fromViem } from '@ensdomains/ens-avatar/viem';

const client = createPublicClient({ chain: mainnet, transport: http() });
const resolver = new AvatarResolver(fromViem(client));

const avatarURI = await resolver.getAvatar('tanrikulu.eth');

支持的外观规格

无

  • ERC 721 (韩语)
  • ERC1155 (英语)

URIs 参考文献

  • HTTP 密码
  • 基础64
  • 森林小组

选项

缓存 (默认: 已禁用)

const avt = new AvatarResolver(provider, { cache: 300 }); // 5 min response cache in memory

自定义IPFS网关 (默认 : https://ipfs.io (英语)(中文(简体) )

const avt = new AvatarResolver(provider, { ipfs: 'https://dweb.link' });

自定义线网关 (默认 : https://arweave.net (中文(简体) )(中文(简体) )

const avt = new AvatarResolver(provider, { arweave: 'https://arweave.net' });

市场 Api 键 (过失: )

const avt = new AvatarResolver(provider, {
  apiKey: {
    opensea: 'YOUR_API_KEY',
  },
});

URL 拒绝列表 (过失:[])

要拒绝的主机名( 包含子域) 。 条目是主机名,而不是URL;匹配忽略了大小写和后缀点.

const avt = new AvatarResolver(client, {
  urlDenyList: ['maliciouswebsite.com'],
});

限制 (故障: 3000 ms, 1 MiB, 5个方向调整, 256 KiB SVG)

  • timeout ——每个HTTP请求作为一个整体的最后期限:方向调整,标题和正文.
  • maxContentLength ——取回的响应机构的最大尺寸(如NFT元数据JSON);较大的响应被拒绝.
  • maxRedirects 按要求重新定向。 每个hop是一个子请求;默认情况下,一个解析度最多给出了~30个HTTP请求(Cloudflare Workers Free's 50).
  • maxSvgLength 内含物的最大长度 / data: SVG活化; 较大者决心 null。 。 。 . utils.sanitizeSVG(svg, { maxLength }) 同样的限制.

数值必须是正整数(maxRedirects 可能为0; NaN, (中文(简体) ), Infinity 而不是无声地使限制失效.

const avt = new AvatarResolver(client, {
  timeout: 8000,
  maxContentLength: 512 * 1024,
  maxRedirects: 3,
  maxSvgLength: 128 * 1024,
});

自定义代理( 只有节点 )

您可以为高级用户提供自定义的 HTTP/ HTTPS 代理 :

import http from 'http';
import https from 'https';

const avt = new AvatarResolver(provider, {
  agents: {
    httpAgent: new http.Agent({ keepAlive: true }),
    httpsAgent: new https.Agent({ keepAlive: true }),
  },
});

安全警报:当您提供自定义代理时, ens- avatar 会把它们当作是 不应用 SSRF 保护。您负责确保您的定制代理拥有适当的安全措施,以防止服务器-Side请求伪造攻击.

如果需要海关人员保护,请用 ssrf-req-filter数字 :

import http from 'http';
import https from 'https';
const { requestFilterHandler } = require('ssrf-req-filter');

const avt = new AvatarResolver(provider, {
  agents: {
    httpAgent: requestFilterHandler(new http.Agent({ keepAlive: true })),
    httpsAgent: requestFilterHandler(new https.Agent({ keepAlive: true })),
  },
});

允许私人IP (错误:虚假) - 说吧 仅限开发

当您需要访问本地主机或私人网络服务时, 本地开发 :

const avt = new AvatarResolver(provider, {
  allowPrivateIPs: true, // Allows localhost, 127.0.0.1, 10.x.x.x, 192.168.x.x, etc.
});

警告声: 这禁用 SSRF 保护 。 只用于本地开发(例如本地IPFS节点,测试服务器). 永远不能在生产中允许。 。 。 .

地方共同发展设想:

  • 本地IPFS节点 : http://127.0.0.1:5001
  • 本地 Ethereum 节点 : http://localhost:8545
  • 私人网络上的容器

说明: 如果您提供自定义代理( 在此情况下您控制安全) , 此旗帜会被忽略 .

云花岗工人

  • 维姆: 用一个 chain。没有适配器,适配器必须要求RPC eth_chainId它这样做时没有viem的要求去除dupe, 因为当一个要求中开始的许诺在另一个要求中等待时,工人就挂了.
  • viem运输: 不允许请求批量( q)http(url, { batch: true }))或(或) batch: { multicall: true } 一个客户在各种请求中共享:两人在排队时都持有电话,其承诺最终会被不同的请求所等待,而请求被搁置.
  • 需要维埃姆 2.35 或晚点 (通用解析器 v3 错误处理).
  • 醚: 6.13 或更晚时间 需要(更早的6.x释放从未超过悬浮请求,即使有 FetchRequest.timeout 页:1 使用 new JsonRpcProvider(url, network, { staticNetwork: true, batchMaxCount: 1 }),所以提供者既不重新发现网络,也不将呼叫按批次进行,这些请求是共享的.

警卫

getMetadata 返回已发布的元数据. 字段类 image, (中文(简体) ), image_url 财务报告和审定财务报表 image_data 是原始的、攻击者控制的值 getAvatar 编号 : getHeader 编号 : utils.getImageURI以证实和消毒.

SS 保护

所有用户生成的 SVG 内容自动进行消毒以防止 XSS 攻击 :

  • 单一的、以解剖法为基础的消毒器(消毒- html 系统 + 键 员额运行 同样的 在浏览器,Node.js,和边缘运行时间(Cloudflare Workers)中——不需要DOM或jsdom.
  • 标记和属性仅限于严格的 SVG 允许列表( 否) script, (中文(简体) ), foreignObject,事件处理器,或外部 href编号 :use编号 :image 目标.
  • CSS 输入 style 属性和 <style> 块被过滤到属性允许列表,每个 CSS 函数必须在函数允许列表上(colors, calc编号 :min编号 :max编号 :clamp,转换,过滤函数,基本形状,计时函数;不 var, (中文(简体) ), env, (中文(简体) ), attr, (中文(简体) ), src, (中文(简体) ), image-set, ...) 演示文稿属性(fill, (中文(简体) ), stroke, (中文(简体) ), filter, (中文(简体) ), mask, (中文(简体) ), clip-path, (中文(简体) ), marker-*) 检查方式相同.
  • url() 到处都是只有内部的 属性, style 属性和 <style> 块:仅可参考 #id 在文档中,所以在外部加载(跟踪,过滤)被屏蔽时,梯度,剪接,口罩,过滤和标记会继续工作. href (和 xlink:href,该名称改为 href)同样仅限于: #id附加时 data:image/* 打开 <image>编号 :<feImage>。 。 。 .
  • 每个 <svg> 元素被绑定在 SVG 命名空间上 (xmlns ),因此无法切换到 XHTML.
  • 常见编辑器输出幸存: Figma 过滤链(fe* 原始语中包含. feDropShadow), Illustrator (英语) <style> 块被一个 CDATA 区域包裹,梯度继承通过 href,以及任何元素的演示文稿属性.

拉斯特·阿凡达斯(Raster avatarspng, (中文(简体) ), jpeg, (中文(简体) ), gif, (中文(简体) ), webp,是否作为 data: URI或远程 URL,在验证后传递——它们作为惰性 <img> 源,而不需重写.

内置对远程 SVGs

SVG可视器的处理取决于其来源:

  • 内置 SVG 链上 <svg>…</svg> 记录和记录 data:image/svg+xml URI —— 返回 已经消毒。 。 。 . getAvatar 编号 : utils.getImageURI 手拿回来 data:image/svg+xml;base64,… URI 有脚本,事件处理器,以及外部引用被剥去.
  • 远程 SVGs - 其记录是: http(s) 在 SVG 中指向的 URL 返回 作为原始的 URL, 未卫生. ens-avatar 是解析器: 对于远程图像, 它返回 地点 图像是活的,而不是它的字节, 所以安全着陆的策略是你的选择。 (解析期间进行的内容类型检查不是安全保障——服务器可以发布广告) image/svg+xml 并仍然返回一个敌对的身体

当您制作一个远程 SVG时, 要么装入一个已经装入沙盒的上下文中 <img src> 标签, CSS background-image,或一个 <image href> 在另一个SVG内部,没有一个执行脚本或加载外部子资源—— 或者说,如果获取字节来服务,存储或内置,则首先用库用于内置SVG的同一种引擎进行消毒:

import { utils as avtUtils } from '@ensdomains/ens-avatar';

// `avatarUrl` came back from resolver.getAvatar(...) and points at an SVG
const svg = await fetch(avatarUrl).then(res => res.text());
const safeSvg = avtUtils.sanitizeSVGDocument(svg, { maxLength: 1024 * 1024 });
// safeSvg: a standalone '<svg …>…</svg>' document, or null if nothing usable remains

sanitizeSVGDocument(svg, { maxLength }): string | null 只返回根 <svg> 元素,因此结果是一个有效的独立文档(在根外的文本,例如 DOCTYPE 的内部子集被删除),并保持原样的白空间. maxLength 默认为 256 KiB. sanitizeSVG(svg, { maxLength }) 是下级函数: 它返回已静态标记为字符串( q)'' ),包括根外的任何文字。 两者都拒绝前方格式错误的输入: a < 不启动标签、注释、 CDATA 部分、 处理指令或声明是无效的 XML( 没有 SVG 渲染器会显示它) , 并且是最昂贵的消毒输入 .

对于SSRF安全获取器(私人地址屏蔽、重定向重新验证、尺寸上限-见下文),使用库自己的获取器,而不是全局的获取器 fetch数字 : const { get } = avtUtils.createFetcher();。 。 。 .

SSRF 保护

默认, ens- avatar 包括内置保护, 防止服务器- Side Request Forgery (SSRF) 在Node.js环境中的攻击. 这阻止了恶意角色使用Avatar URL来探测内部网络.

默认行为 (建议生产):

  • 仅限 http: 财务报告和审定财务报表 https: 获取 URL
  • QQ 仅允许全球roubable unicast地址 : 回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回回
  • QQ 每一次重定向 hop 重新验证, 并请求除 Accept编号 :Range (API 密钥) 一旦重定向离开原始来源就会被丢弃
  • * 每项请求都有一个涵盖主体的最后期限,响应机构被限制大小,方向调整有限(见 限制(中文(简体) )

自定义代理: 如果您提供了自己的HTTP/HTTPS代理, ens-avatar将会在不应用SSF保护的情况下使用它们 。 您负责您的定制代理.

地方发展设置 allowPrivateIPs: true 当您需要访问本地服务(例如本地IPFS节点)时,可禁用SSF保护。 不要用这个生产.

见 自定义代理 详细情况.

看守阅读的CCIP

ens-avatar 从未让 CCIP 阅读 (EIP-3668) 请求自己: 脱链取景由 :  链式客户端( 供应商或viem) ccipRead),与客户端的HTTP堆栈和限制. 一个名字的网关是攻击者控制的输入,所以在服务器上:

用你的客户的钩子保护它——viem: ccipRead: { request } 打开 createPublicClient; 醚类: FetchRequest.registerGetUrl - 里面还有:

  • 检查您实际要求的 URL,即替换后 {sender} 财务报告和审定财务报表 {data} 输入网关模板。 检查模板还不够 : https://{data}/ 有数据 0x7f000001 目标 127.0.0.1启用 avtUtils.validateUrl(url)。 。 。 .
  • 别让 fetch 跟踪方向. 使用 redirect: 'manual' 运行 validateUrl 每页 Location 跳,有一个跳限.
  • 每项请求都有约束力 (超时,响应大小)和整个取景点:尝试和嵌入取景点的网关 URL数量(采行者停止于 10, MAX_CCIP_REDIRECTS;viem没有自己的限制).
  • 在节点上,还检查已解决的地址. validateUrl 仅查看 URL: 一个网关主机名,其DNS在私人地址的指针通过它. 通过一个检查它连接的IP的代理(例如undici),使网关请求 Agent 带有验证 lookup,或 ssrf-req-filter) (中文(简体) ).

服役的阿凡达人

如果您从自己的来源代理或保留了可视化字节, 请发送 X-Content-Type-Options: nosniff 和沙箱式CSP,例如: Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; sandbox,因此敌对文件不能作为页面运行在您的域名上.


安全分遣队

虽然 " 救援者 " 执行安全措施,帮助防范XSS和SSF的袭击, 您对申请的安全负最终责任我们强烈建议:

  • 在投入生产前自行进行安全审计
  • 执行适合您使用的更多安全层
  • 不断更新库以接收安全补丁
  • 处理用户生成的内容时遵循安全最佳做法
  • 正确配置所有与安全有关的环境选项

这个图书馆是在没有保证的情况下提供的"as-is". 维护者对使用该图书馆的应用程序中的任何安全弱点不负责任.

演示

  • 用 INFURA KEY env 变量创建.env 文件

  • 构建库

  • 节点示例

node example/node.js ENS_NAME
  • 浏览器示例
pnpm build:demo
http-server example

版本与发布记录

@ensdomains/ens-avatar 共发布 38 个版本,首次发布于 2022/02/22;过去 12 个月发布了 8 个版本。

版本发布日期距今
2.0.0-alpha.4alpha2026/10/081 个月前
1.0.6latest2026/10/011 个月前
1.0.52026/09/301 个月前
2.0.0-alpha.32026/09/251 个月前
2.0.0-alpha.22026/06/234 个月前
2.0.0-alpha.12026/04/077 个月前

关于 @ensdomains/ens-avatar 的常见问题

@ensdomains/ens-avatar 是什么?

用于节点和浏览器的Avatar解析器库.

如何安装 @ensdomains/ens-avatar?

在项目目录运行 npm install @ensdomains/ens-avatar,或使用 pnpm add / yarn add / bun add。

@ensdomains/ens-avatar 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@ensdomains/ens-avatar 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@ensdomains/ens-avatar 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@ensdomains/ens-avatar 可以商用吗?

@ensdomains/ens-avatar 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@ensdomains/ens-avatar 的下载量有多少?

根据 npm 官方下载统计,@ensdomains/ens-avatar 在 2026/10/14 – 2026/11/12 这 30 天内被下载 2,566 次,日均约 86 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ensdomains/ens-avatar 还在维护吗?

最新版本 1.0.6 发布于 2026/10/01(1 个月前);至今共发布 38 个版本,其中过去 12 个月发布了 8 个;首次发布于 2022/02/22。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。