html解析器遇到标签时立即提取href属性原始值并存入dom节点,不验证、不请求、不解析url;href属性值在dom中自动标准化为绝对url,而getattribute('href')保留原始字符串。

HTML解析器遇到标签时会立即提取href属性值
浏览器不会等整个文档加载完才处理超链接,<a></a>标签在词法分析阶段就被识别为“开始标签Token”,解析器一旦读到href属性,就会立刻提取其原始字符串值(不解析URL、不发起请求、不校验格式),存入对应DOM节点的href属性中。这个过程发生在DOM树构建早期,甚至早于CSSOM加载。
常见错误现象包括:
- 相对路径写成
href="https://www.php.cn/link/ed65d29dbae22c48a8a59a8c6b7ef102"(开头多空格)→ 浏览器按字面量保存,后续点击跳转时被当作绝对路径https://site.com/%20/css/style.css -
href="javascript:void(0)"被误认为“无跳转” → 实际仍会触发click事件,且部分屏幕阅读器将其识别为可跳转链接,影响可访问性 - 未声明
rel="noopener"的target="_blank"链接 → 新页面可通过window.opener反向控制原页面,存在安全风险
href属性值在DOM中会被自动标准化为完整URL
你用document.querySelector('a').href读到的永远是解析后的绝对URL,哪怕HTML里写的是href="./page.html"或href="/api/data"。这是因为浏览器在把字符串赋给DOM节点href属性时,已根据当前页面URL做了resolve处理——底层调用的是类似new URL(value, base)的逻辑。
这意味着:
- 不能靠
el.href === el.getAttribute('href')判断是否被修改过;前者是解析后值,后者是原始HTML字符串 - 服务端渲染时若依赖
href属性做路由匹配,应优先读getAttribute('href')而非.href - 使用
URL.canParse()校验前,必须传原始getAttribute('href'),否则总返回true
解析阶段不验证链接有效性,也不预加载资源
<a></a>标签本身在HTML解析期完全不触发网络请求。即使写href="https://example.com/404"或href="file:///etc/passwd",只要没用户点击或脚本调用el.click(),就不会产生任何HTTP请求或错误日志。
但有两个例外场景会提前介入:
- 带
rel="preload"的<link>可预加载,但<a></a>不支持该rel值 - Chrome 120+对
rel="next"或rel="prefetch"的<a></a>会在空闲时预取,但这是渲染后期行为,与HTML解析无关 - 服务端HTTP响应头含
Link: <url>; rel=preload</url>才真正影响预加载时机
JavaScript动态创建时href解析逻辑一致
用document.createElement('a')再设el.href = './test',其标准化行为和HTML中声明完全相同:会基于当前文档URL解析。但注意一个关键差异——如果元素尚未插入DOM,el.href读出来可能是空字符串或"about:blank",因为缺少有效的baseURI上下文。
稳妥做法是:
- 先插入DOM(哪怕
el.style.display = 'none'),再读.href - 或显式构造:
new URL('./test', document.baseURI).href - 避免直接拼接:
window.location.origin + '/path'在非标准端口或子路径下容易出错
最容易被忽略的是:HTML解析器对<a></a>的处理完全不关心协议、域名、路径是否存在,它只做字符串提取和基础标准化。所有“链接是否有效”“是否跨域”“是否需要鉴权”的判断,都推迟到用户交互或脚本主动调用时才发生。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











