使用Refit发送含Uri属性的类作为POST接口参数时Uri值异常问题
问题根因
该问题和Refit框架本身无关,是Newtonsoft.Json默认的Uri类型序列化逻辑导致的:默认序列化Uri时会调用ToString()方法,对于file://协议的Uri,ToString()会省略协议前缀,仅返回路径部分。
定位方法
在客户端本地直接序列化测试即可复现问题:
var test = new SomeClass { Uri = new Uri("file:///var/share") }; var serializeResult = JsonConvert.SerializeObject(test); // 输出结果为 {"Uri":"/var/share"},和服务端收到的内容一致,可确认是序列化环节的问题
解决方案
提供两种可行的修复方式,可根据业务场景选择:
- 方案1:自定义Uri序列化转换器(无侵入修改,不用调整原有实体结构)
首先实现自定义JsonConverter:
public class UriAbsoluteConverter : JsonConverter<Uri> { public override void WriteJson(JsonWriter writer, Uri value, JsonSerializer serializer) { // 序列化时取完整的AbsoluteUri writer.WriteValue(value?.AbsoluteUri); } public override Uri ReadJson(JsonReader reader, Type objectType, Uri existingValue, bool hasExistingValue, JsonSerializer serializer) { var uriStr = reader.Value?.ToString(); return string.IsNullOrWhiteSpace(uriStr) ? null : new Uri(uriStr); } }
将转换器注册到Refit的序列化配置中:
var jsonSettings = new JsonSerializerSettings { Converters = new List<JsonConverter> { new UriAbsoluteConverter() } }; var refitSettings = new RefitSettings(new NewtonsoftJsonContentSerializer(jsonSettings)); _apiRefit = RestService.For<ISomeApi>("http://localhost:5000", refitSettings);
- 方案2:调整实体属性类型(改动最小,无需额外配置)
将实体类的Uri属性改为string类型,赋值时直接传入Uri的AbsoluteUri值,服务端也对应调整为string接收,需要使用Uri类型时再手动转换即可:
[Serializable] public class SomeClass { // 赋值示例:someClass.Uri = yourUri.AbsoluteUri; public string Uri { get; set; } }
两种方案均能保证传输的Uri携带完整的协议前缀,服务端可正常解析。
内容的提问来源于stack exchange,提问作者Ohad Horesh
相关产品推荐
相关产品推荐

