C# WebClient请求含|字符URL时自动编码为%7C报错的解决方法
问题根因
WebClient底层依赖HttpWebRequest实现请求发送,默认会按照RFC 3986规范对URL中的非保留字符做百分号编码,URL里的竖线|会被自动转成%7C。而访问的NIST老旧CGI接口没有实现查询串的URL解码逻辑,收到转义后的%7C就会直接返回you have supplied an ill-formed request错误。
浏览器能正常打开是因为部分浏览器对竖线这类特殊字符的发送逻辑和.NET默认实现不同,不会主动转义|。
可行解决方案
方案1:自定义WebClient关闭自动转义(.NET Framework 环境推荐)
通过重写WebClient的请求创建逻辑,反射调用内部方法关闭URI自动转义,不需要大幅改动原有业务代码逻辑:
首先引入反射命名空间:
using System.Reflection;
然后实现自定义WebClient类:
public class RawUriWebClient : WebClient { protected override WebRequest GetWebRequest(Uri address) { var request = (HttpWebRequest)base.GetWebRequest(address); // 反射调用内部SetUri方法,关闭自动转义 var setUriMethod = typeof(HttpWebRequest).GetMethod("SetUri", BindingFlags.NonPublic | BindingFlags.Instance); // 第二个参数dontEscape设为true,即不对URI做百分号编码 setUriMethod.Invoke(request, new object[] { address, true }); return request; } }
调用时替换原有WebClient即可:
ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; using var client = new RawUriWebClient(); // 直接传入带原始|的URL,不要手动转义 string html = client.DownloadString("https://physics.nist.gov/cgi-bin/cuu/CCValue?mal|ShowSecond=Browse&First=malc2");
方案2:使用新版HttpClient(.NET Core/.NET 5+ 环境推荐)
新版.NET中,HttpClient默认不会强制转义URL中的竖线字符,不需要做额外反射配置,直接调用即可:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; using var client = new HttpClient(); string html = await client.GetStringAsync("https://physics.nist.gov/cgi-bin/cuu/CCValue?mal|ShowSecond=Browse&First=malc2");
注意:不要尝试手动把URL里的
|替换为%7C传入,该NIST接口不会对查询参数做解码处理,必须传入原始|字符才能返回正常内容。
方案3:手动组装原始请求(无反射兼容方案)
如果不想使用反射修改内部逻辑,可以直接通过TcpClient手动拼接HTTP请求行,完全绕过.NET内置的URI编码逻辑,不过这种方法需要自行处理HTTPS握手、重定向、压缩等逻辑,复杂度较高,非特殊场景不推荐。
内容的提问来源于stack exchange,提问作者Wollmich
相关产品推荐
相关产品推荐

