C# 即使路径中有百分比编码部分,如何可靠地获取实际URL?

C# 即使路径中有百分比编码部分,如何可靠地获取实际URL?,c#,asp.net,asp.net-mvc,iis,C#,Asp.net,Asp.net Mvc,Iis,IIS和ASP.NET(MVC)在处理路径中带有%编码的URL时(不是查询字符串;查询字符串可以)。我怎样才能避开这件事?i、 e.如何获取请求的实际URL 例如,如果我导航到/x%3Fa%3Db和(分别)导航到/x?a=b,它们都将.Request.Url报告为/x?a=b,因为路径中的编码数据报告不正确;URL变量包含一个解码值;QUERY\u字符串变量包含仍然编码的查询。我们不能只在URL部分调用encode,因为它也包含原始形式的/等-如果我们盲目地对整个内容进行编码,我们将得到不需要的

IIS和ASP.NET(MVC)在处理路径中带有%编码的URL时(不是查询字符串;查询字符串可以)。我怎样才能避开这件事?i、 e.如何获取请求的实际URL


例如,如果我导航到
/x%3Fa%3Db
和(分别)导航到
/x?a=b
,它们都将
.Request.Url
报告为
/x?a=b
,因为路径中的编码数据报告不正确;
URL
变量包含一个解码值;
QUERY\u字符串
变量包含仍然编码的查询。我们不能只在
URL
部分调用encode,因为它也包含原始形式的
/
等-如果我们盲目地对整个内容进行编码,我们将得到不需要的
%2f
值;但是,您可以将其分离并发现问题案例:

private static readonly Regex simpleUrlPath = new Regex("^[-a-zA-Z0-9_/]*$", RegexOptions.Compiled);
private static readonly char[] segmentsSplitChars = { '/' };
// ^^^ avoids lots of gen-0 arrays being created when calling .Split
public static Uri GetRealUrl(this HttpRequest request)
{
    if (request == null) throw new ArgumentNullException("request");
    var baseUri = request.Url; // use this primarily to avoid needing to process the protocol / authority
    try
    {
        var vars = request.ServerVariables;
        var url = vars["URL"];
        if (string.IsNullOrEmpty(url) || simpleUrlPath.IsMatch(url)) return baseUri; // nothing to do - looks simple enough even for IIS

        var query = vars["QUERY_STRING"];
        // here's the thing: url contains *decoded* values; query contains *encoded* values

        // loop over the segments, encoding each separately
        var sb = new StringBuilder(url.Length * 2); // allow double to be pessimistic; we already expect trouble
        var segments = url.Split(segmentsSplitChars);
        foreach (var segment in segments)
        {
            if (segment.Length == 0)
            {
                if(sb.Length != 0) sb.Append('/');
            }
            else if (simpleUrlPath.IsMatch(segment))
            {
                sb.Append('/').Append(segment);
            }
            else
            {
                sb.Append('/').Append(HttpUtility.UrlEncode(segment));
            }
        }
        if (!string.IsNullOrEmpty(query)) sb.Append('?').Append(query); // query is fine; nothing needing
        return new Uri(baseUri, sb.ToString());
    }
    catch (Exception ex)
    { // if something unexpected happens, default to the broken ASP.NET handling
        GlobalApplication.LogException(ex);
        return baseUri;
    }
}

虽然这种想法很受欢迎,但StackOverflow不是一个片段站点,也不是一个发布你想出来的东西的地方,比如博客。你的问题和答案的时间戳表明你已经准备好在这里发布这两个问题。请只发布您真正需要帮助的问题。有更合适的方式与社区共享信息。@Chris。允许回答作为提问的一部分的决定也是非常有意的——代码是非常有意地添加的。我知道:我在那个团队工作。此外,在我修复了一个错误后,这个代码已经作为请求的一部分由用户在“meta”上共享。Tl;博士:回答你自己的问题是明确可以的,只要问题和答案是正确的和适当的。