首页 新闻 赞助 找找看

asp.net core MVC中URL编码问题

0
悬赏园豆:20 [已解决问题] 解决于 2018-01-12 20:53

目的:要在URL中传递一个参数到服务端。
但是name参数中有保留字符/,所以先用UrlEncode进行编码。
测试代码如下:

[Fact]
public async void GetByName_TestAsync()
{
    var name = WebUtility.UrlEncode("aa/bbc");
    var response = await Client.GetAsync($"api/users/{name}"); 
    var user = await response.Content.ReadAsAsync<UserDto>();      
    user.Should().NotBeNull(); 
}

服务端API:

[HttpGet("{name}")]
public async Task<UserDto> Get(string name)
{
    return await _userAppService.GetUserByNameAsync(name);
}

结果查不到name=aa/bbc的user。

通过debug发现,请求的结果是404,本来以为是MVC解码了URL再进行路由匹配,因此请求的路径就变成了aa/bbc。但通过在浏览器中发起请求,就可以等到编码后的值aa%2Fbbc,所以判断这是HttpClient的问题,它在发起请求之前对URL作了手脚。

那么如何通过URL传递带有保留字符(/)的参数呢?

< >
分享
最佳答案
2

为了验证是不是HttpClient的问题,新建了一个控制台程序验证一下

        static void Main(string[] args)
        {
            var client = new HttpClient()
            {
                BaseAddress = new Uri("http://localhost:5000/")
            };
            var name = "b/c";
            name = WebUtility.UrlEncode(name);
            var request = new HttpRequestMessage(HttpMethod.Get, $"users/{name}");
            var task = client.SendAsync(request);
            task.Wait();
            var response = task.Result;
            System.Console.WriteLine(response.StatusCode);
            var task2 = response.Content.ReadAsStringAsync();
            task2.Wait();
            System.Console.WriteLine(task2.Result);
            Console.WriteLine("Hello World!");
        }

打印结果如下:

OK
Demo.UserDto
Hello World!

返回了正确的结果,因此证明了不是HttpClient的问题。但是可以发现,唯一的不同之处就是在测试中使用的Client不是new HttpClient而是通过TestServer.CreateClient创建的,于是clone下aspnet/Hosting的源代码,一探TestServer的究竟。最终发现问题出在如下代码中:

req.Path = PathString.FromUriComponent(request.RequestUri);

TestServer创建的HttpClient中增加了一个自定义的HttpMessageHandler,其中就把我们传递给ClientRequest进行拆装,如上所示,通过PathString.FromUriComponent方法重新构造了请求地址,这个方法把URL给decode了,所以导致发送的请求路径出错了。

总结:asp.net core MVC并不存在所谓的编码问题,是集成测试的时候TestServer搞的鬼。

蝌蝌 | 初学一级 |园豆:158 | 2018-01-12 20:53

如果URL中包含"%2F",可能在某些Server(例如:IIS, Http.sys)上有问题,刚刚部署到IIS中验证了一下,确实如果URL中含有%2F,还是会404.

所以最好还是把含有"%2F"的片段放在QueryString中,如果执意要放在路径中,还是用base64编码吧。

详见:https://github.com/aspnet/Hosting/issues/1310

蝌蝌 | 园豆:158 (初学一级) | 2018-01-13 08:23
其他回答(3)
0

给个思路,你在传递参数的时候,先对参数处理/替换,如:

你的url: https://abc.com?parms=test?ceshi

?替换成 “_”

=>处理后的url:https://abc.com?parms=test_ceshi

----------------------

你的url: https://abc.com?parms=test?ceshi&ceshia

?替换成 “_”,&替换成“__”

=>处理后的url:https://abc.com?parms=test_ceshi__ceshia

----------------------

处理完毕以后在接收端解析参数的时候对“_”,"__" 还原即可,当然这样做不严谨,需要分析下你的参数会不会本身也有_的场景,如果有,你可以换成别的不被编码解码的字符  

顾星河 | 园豆:7169 (大侠五级) | 2018-01-11 15:43
0

我本地试了一下,如果没有用UrlEncode的话,确实是取不到全部值,但是加了UrlEncode 后,是可以获取到全部值的.

在本地使用
[HttpGet("api/users/{name}")]
以及

[HttpGet]
[Route("api/users/{name}")]

都可以成功获取

收获园豆:20
BUTTERAPPLE | 园豆:3190 (老鸟四级) | 2018-01-11 16:12

不好意思,问题中的参数填错了,应该是aa/bbc,问题已更新。

支持(0) 反对(0) 蝌蝌 | 园豆:158 (初学一级) | 2018-01-11 18:35

@蝌蝌: 这种 Reserved character 最好的解决办法,还是把其替换成其他字符,然后再进行转义。维基百科上就是这样做的。

支持(0) 反对(0) BUTTERAPPLE | 园豆:3190 (老鸟四级) | 2018-01-11 20:16

@BUTTERAPPLE: 发现不是MVC的问题,问题已更新。

支持(0) 反对(0) 蝌蝌 | 园豆:158 (初学一级) | 2018-01-12 15:22
0

或许用转义字符呢?aa\?bb 试试

Shendu.CC | 园豆:2138 (老鸟四级) | 2018-01-11 17:33
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册