ServiceStack URI encoding

本文关键字:encoding URI ServiceStack | 更新日期: 2023-09-27 18:31:52

我已经使用ServiceStack一段时间了,我对它提供的功能非常满意。已经用它实现了服务器服务,它就像一个魅力。

但是,最近我遇到了使用必须正确编码的复杂 URL 调用其他服务的问题。

代码如下:

请求:

[Route("/instruments/{Names}")]
internal class Request
{
    public List<string> Names { get; set; }
}

方法调用:

var request = new Request { Names = list };
var c = new JsonServiceClient("http://host:12345/");
Response[] response;
try
{
    response = c.Get<Response[]>(request);
}
catch (WebServiceException ex)
{
    HandleWebException(ex, list);
    yield break;
}

现在的问题是,有时名称可以包含特殊字符,例如空格或/。我想对这些属性进行编码。例如,我希望能够使用以下参数调用远程服务:"D''S N"应该编码为"D%5CS%20N"。因此,被调用的 URL 应如下所示:

http://host:12345/instruments/D%5CS%20N

现在的问题是JsonServiceClient在这里进行了错误的编码。我所说的实际上是:

http://host:12345/instruments/D/S%20N

用显然是错误的。任何如何解决这个问题的帮助都是合适的。

ServiceStack URI encoding

您不应该在 PathInformation 中注册像 List<T> 这样的复杂类型,请尝试使用单个字符串:

[Route("/instruments/{Name}")]
public class Request
{
    public string Name { get; set; }
}

或者把它从/pathinfo 中取出,这样它就会在 QueryString 上被序列化为复杂类型:

[Route("/instruments")]
public class Request
{
    public List<string> Names { get; set; }
}

我相信ServiceStack可以在这里得到改进。

如果我使用如下定义的请求 DTO:

[Route("/hello/{Name}/{Message}")]
public class Hello
{
    public string Name { get; set; }
    public string Message { get; set; }
}

然后客户端像这样调用:

var resp = cli.Get(new Hello { Message = "test", Name = "foo/bar" });

将失败。如果我用反斜杠替换斜杠,也会发生同样的情况。

我已经对 ServiceStack 做了一个补丁来修复这种行为(也适用于反斜杠),以便 Name 将被正确编码客户端和解码的服务器端。Demis,这是你可能有兴趣看看的东西吗?

顺便说一句,这与Java Jersey开箱即用.....

我遇到了同样的问题。 我的字符串不是一个复杂的对象。 只是一个带有斜杠的字符串。 看起来服务堆栈实际上正在正确接收 URL 编码的字符串。然后,Servicestack 似乎在将 URL 编码字符串传递给路由之前对其进行解码(这只是我的猜测),而不是使用请求 DTO 中的路由信息首先确定 URL 的哪一部分是路由,哪一部分是参数,然后路由,然后解码 URL 编码参数。我从服务堆栈收到如下错误:

Handler for Request not found (404):
  Request.HttpMethod: GET
  Request.PathInfo: /QuoteFeed/GetQuote/ACO/X CN
  Request.QueryString: 
  Request.RawUrl: /QuoteFeed/GetQuote/ACO%2FX%20CN

请求定义如下:

[Route("/QuoteFeed/GetQuote/{Symbol}", Summary = "Retreive a price quote for the requested symbol.")]
public class GetQuote : IReturn<QuoteDataResponse>
{
    [DataMember, ProtoMember(1)]
    [ApiMember(Name = "Symbol",
         Description = "The symbol, in the providers given format, for which a quote should be given.",
         DataType = "string",
         IsRequired = true)]
    public string Symbol { get; set; } 
}
要求客户端将斜杠

替换为服务将交换回斜杠的其他特殊字符似乎很脆弱。 解决此问题的唯一方法是通过 POST 强制请求吗?

编辑 1

这是我让它工作的最佳尝试:

在客户端:

dim client = new JsonServiceClient (My.Settings.MarketDataServiceUri)
dim request = New GetQuote
request.Symbol =  WebUtility.UrlEncode(txtBoxSymbol.Text.ToUpperInvariant)

在服务器端(在 AppHost.Init 中):

base.RequestBinders.Add(typeof(GetQuote), httpReq =>
{
    var requestPath = string.Empty;
    if (typeof(GetQuote).GetCustomAttributes(typeof(RouteAttribute), true
                                     ).FirstOrDefault() is RouteAttribute dnAttribute)
    {
        requestPath = dnAttribute.Path;
    }
    var routePath = requestPath;
    var paramIndex = requestPath.IndexOf("{");
    if (paramIndex > 0)
    {
        routePath = requestPath.Substring(0, paramIndex);
    }
    return new GetQuote
    {
        Symbol = WebUtility.UrlDecode(httpReq.PathInfo.Replace(routePath, string.Empty))
    };
});

这真的很丑陋,但我找不到任何其他方法。 传入的符号必须具有斜杠,因为这是下游报价提供程序要求的格式,也是用户期望输入的格式。 这是最好的方法吗?