在我正在使用的.NET Core 2.1 Web API上,我有一个POST方法接收仅具有一个属性的JSON对象,如下所示:
{
"longURL": "http://foo.example.com/path/path/path/path/path/pfad"
}
以及方法的标题:
public async Task<ActionResult<ShortenerOutputDto>> CreateAsync([FromBody]
ShortenerInputDto input)
但是如果输入的JSON包含一些特殊字符,我会遇到异常,如下所示:
{
"longURL": "http://foo.example.com/path/path/path/path/path/pfad¿"
}
请注意,最后一个(¿)是有问题的字符。 我得到的例外是:
System.Text.DecoderFallbackException: Unable to translate bytes [BF] at index 75 from specified code page to Unicode.
at System.Text.DecoderExceptionFallbackBuffer.Throw(Byte[] bytesUnknown, Int32 index)
at System.Text.DecoderExceptionFallbackBuffer.Fallback(Byte[] bytesUnknown, Int32 index)
at System.Text.DecoderFallbackBuffer.InternalFallback(Byte[] bytes, Byte* pBytes, Char*& chars)
at System.Text.UTF8Encoding.GetChars(Byte* bytes, Int32 byteCount, Char* chars, Int32 charCount, DecoderNLS baseDecoder)
at System.Text.DecoderNLS.GetChars(Byte[] bytes, Int32 byteIndex, Int32 byteCount, Char[] chars, Int32 charIndex, Boolean flush)
at System.Text.DecoderNLS.GetChars(Byte[] bytes, Int32 byteIndex, Int32 byteCount, Char[] chars, Int32 charIndex)
at Microsoft.AspNetCore.WebUtilities.HttpRequestStreamReader.ReadIntoBuffer()
at Microsoft.AspNetCore.WebUtilities.HttpRequestStreamReader.Read(Char[] buffer, Int32 index, Int32 count)
at Newtonsoft.Json.JsonTextReader.ReadData(Boolean append, Int32 charsRequired)
at Newtonsoft.Json.JsonTextReader.ParseValue()
at Newtonsoft.Json.JsonTextReader.Read()
at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
问题在于进入控制器方法之前引发了异常。
那么,有办法避免这种情况吗?我想发送BadRequest,以防输入无法解码。
更新
基于@jdweng的答案,我添加了以下转换器类:
public class HtmlEncodingConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(String);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return System.Web.HttpUtility.HtmlDecode((string)reader.Value);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(System.Web.HttpUtility.HtmlEncode((string)value));
}
}
并注册为JSONOptions:
services.AddMvc()
.AddJsonOptions (opt => opt.SerializerSettings.Converters.Add(new HtmlEncodingConverter()));
但是如果请求中有某些特殊字符,则不会选中ReadJson或WriteJson。
因此,看来解码或解码发生在Core尝试转换输入之前。真的很奇怪。
UPDATE II
原始HTTP请求消息:
POST /create HTTP/1.0
Host: localhost:5000
Content-Length: 80
Content-Type: application/json
{
"longURL" : "http://foo.example.com/path/path/path/path/path/pfad¿"
}
答案 0 :(得分:1)
最后,我最终添加了一个异常过滤器,如下所示:
InvalidOperationException
...并在startup.cs中注册:
public class DecoderFallbackExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (context.Exception.GetType() == typeof(DecoderFallbackException))
context.Result = new BadRequestObjectResult(ShortURLResponse.InvalidURL());
}
}
也许这不是我最初期望的解决方案,但是可以使我控制每种情况下应该采取的行动。
此外,我可以再次向该方法添加输入参数,然后重新启用单元测试。 https://github.com/aspnet/AspNetCore/issues/8676
顺便说一句,似乎此行为将在ASP.NET Core 3.0中得到增强。 https://github.com/aspnet/AspNetCore/issues/3959