application/dns-message采用何种编码?DoH请求体解码异常求助
问题核心原因
- 混淆了DoH两种请求方式的编码规则
DoH标准中base64url编码仅用于GET请求的dns查询参数,你当前拿到的是POST请求的application/dns-message格式请求体,本身就是原始DNS二进制报文,不需要做任何base64转换操作,你执行的「ArrayBuffer转base64再做base64url解码」属于多余操作,直接破坏了原始报文结构。 - 错误将二进制DNS报文直接转为可读字符串
DNS报文是按固定二进制协议结构封装的,并非纯文本内容,直接把二进制字节转成字符串必然会出现大量不可见字符,看起来就是乱码,你需要按DNS协议规范逐字段解析报文内容。
解决步骤
- 第一步:区分请求类型处理报文
- 若为POST请求:直接使用接收到的Uint8Array原始数据即可,无需任何编码转换
- 若为GET请求:从URL的
dns查询参数中获取base64url编码的字符串,先将其转为标准base64格式,再解码得到二进制DNS报文
- 第二步:按DNS协议结构解析报文
你示例中的解码结果里的apnx-matchdotomicom已经是DNS请求的域名部分可读内容,只是缺少了DNS报文里的标签长度分隔符,你可以按以下逻辑解析域名字段:
function parseDomainName(buffer, offset) { let domain = []; let len = buffer[offset]; while (len !== 0) { // 处理指针跳转(压缩域名的情况) if ((len & 0xC0) === 0xC0) { const pointer = ((len & 0x3F) << 8) | buffer[offset + 1]; domain.push(parseDomainName(buffer, pointer).domain); offset += 2; break; } offset++; domain.push(String.fromCharCode(...buffer.slice(offset, offset + len))); offset += len; len = buffer[offset]; } return { domain: domain.join('.'), offset: offset + 1 }; }
直接调用该方法传入原始Uint8Array报文和域名起始偏移量(通常DNS报文前12字节是固定头部,域名从第12字节开始),就能正确解析出请求的完整域名。
内容的提问来源于stack exchange,提问作者ajaleksa
相关产品推荐
相关产品推荐

