HttpWebRequest URL 转义

4

我知道,这个标题听起来好像这个问题已经被解决很多次了。但是我正在努力应对一个特定的情况,我非常困惑。希望有经验的C#程序员能指点我正确的方向。

以下是代码:

string serviceURL = "https://www.domain.com/service/tables/bucketname%2Ftables%2Ftesttable/imports";
HttpWebRequest dataRequest = (HttpWebRequest)WebRequest.Create(serviceURL);

现在当我快速查看 dataRequest 时,发现:

RequestUri: {https://www.domain.com/service/tables/bucketname/tables/testtable/imports}

看起来HttpWebRequest已将%2F更改为/。 然而,服务器需要请求的Uri与serviceURL完全相同,包含%2F

有没有办法让HttpWebRequest类调用Url:

https://www.domain.com/service/tables/bucketname%2Ftables%2Ftesttable/imports

非常感谢!我在这里完全不知所措... -Brett


请查看这个问题,在答案中有一个解决方法:https://dev59.com/CXRA5IYBdhLWcg3w6SbZ - Kyle Trauberman
当然。还是一样的:RequestUri: {https://www.domain.com/service/tables/bucketname/tables/testtable/imports} - Brett
@Kyle,谢谢,我会试一下。但它看起来相当不专业。似乎应该有更好的方法。PHP 处理这个很好。 - Brett
@Kyle。可以工作!虽然有点奇怪的hack,但是它可以工作! - Brett
3个回答

3

0
只要问题在于%2F未转义为“/”,就有解决方案。其中一个涉及黑客技巧,对于较新版本的.Net,则需要使用app.config设置。请查看此处:如何使System.Uri不在路径中取消转义%2f(斜杠)? 然而,我仍然需要弄清楚如何防止它取消转义一些特定转义字符,例如'('和')'(%28和%29)。我已经尝试了所有设置和黑客技巧,以防止Uri类提供部分取消转义的WebRequest路径。这些解决方案可以很好地防止取消转义%2F,但无法防止取消转义%28和%29以及可能大多数其他特定转义字符。
似乎WebRequest正在专门从Uri对象中请求1个值来创建“GET /path HTTP/1.1”语法:Uri.PathAndQuery,它再次调用其UriParser.GetComponents。
如果您想从mediafire下载并且其中包含%28和%29字符,则会进入无限重定向循环,因为.Net会不断将%28和%29更改为'('和')'并跟随重定向(异常:“尝试了太多自动重定向”)。

如果您被卡住了,找不到防止某些字符反转义的方法,那么这是一个解决方案。

目前我惟一发现能够重写此功能(目前使用 .Net 4.6),并提供自己的 PathAndQuery 的方法是通过继承 UriParser 并对其使用进行修改。

public sealed class MyUriParser : System.UriParser
{
    private UriParser _originalParser;
    private MethodInfo _getComponentsMethod;

    public MyUriParser(UriParser originalParser) : base()
    {
        if (_originalParser == null)
        {
            _originalParser = originalParser;

            _getComponentsMethod = typeof(UriParser).GetMethod("GetComponents", BindingFlags.NonPublic | BindingFlags.Instance);
            if (_getComponentsMethod == null)
            {
                throw new MissingMethodException("UriParser", "GetComponents");
            }
        }
    }

    private static Regex rx = new Regex(@"^(?<Scheme>[^:]+):(?://((?<User>[^@/]+)@)?(?<Host>[^@:/?#]+)(:(?<Port>\d+))?)?(?<Path>([^?#]*)?)?(\?(?<Query>[^#]*))?(#(?<Fragment>.*))?$",RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Singleline);
    private Match m = null;

    protected override string GetComponents(Uri uri, UriComponents components, UriFormat format)
    {
        var original = (string)_getComponentsMethod.Invoke(_originalParser, BindingFlags.InvokeMethod, null, new object[] { uri, components, format }, null);
        if (components == UriComponents.PathAndQuery)
        {
            var reg = rx.Match(uri.OriginalString);
            var path = reg.Groups["Path"]?.Value;
            var query = reg.Groups["Query"]?.Value;
            if (path != null && query != null) return $"{path}?{query}";
            if (query == null) return $"{path}";
            return $"{path}";
        }

        return original;
    }

}

然后通过将其UriParser替换为此实例,将其黑客入Uri实例中。

    public static Uri CreateUri(string url)
    {
        var uri = new Uri(url);
        if (url.Contains("%28") || url.Contains("%29"))
        {
            var originalParser = ReflectionHelper.GetValueByReflection(uri, "m_Syntax") as UriParser;
            var parser = new MyUriParser(originalParser);
            ReflectionHelper.SetValueByReflection(parser, "m_Scheme", "http");
            ReflectionHelper.SetValueByReflection(parser, "m_Port", 80);
            ReflectionHelper.SetValueByReflection(uri, "m_Syntax", parser);
        }
        return uri;
    }

由于UriParser的工作方式,通常需要注册以设置其端口和方案名称,因此这两个值必须通过反射设置,因为我们没有以正确的方式进行注册。我还没有找到注册“http”的方法,因为它已经存在。ReflectionHelper只是我拥有的一个类,但可以很快地用普通的反射代码替换它。
然后像这样调用它:
HttpWebRequest dataRequest = (HttpWebRequest)WebRequest.Create(CreateUri(serviceURL));

-1
string serviceURL = Uri.EscapeUriString("https://www.domain.com/service/tables/bucketname%2Ftables%2Ftesttable/imports");

这看起来像是正确的轨迹,但它将 %2F 转换成了 %252F(转义百分号)。 - Brett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接