You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core OData查询过滤器含特殊字符解析失败求助

解决OData查询过滤器含特殊字符的解析失败问题

问题场景

我们通过OData查询过滤器向WebAPI发起请求,示例请求如下:

https://localhost:44372/v1/odata/xxx/xxxx/xxxxxx?$select=type_of_secur&$filter=type_of_secur eq 'Ability & ABS'

或

https://localhost:44372/v1/odata/xxx/xxxx/xxxxxx?$select=type_of_secur&$filter=type_of_secur in ('Ability & ABS')

其中type_of_secur是枚举类型,需要根据过滤器中的文本匹配枚举字符串,关联数据库中的整数值返回结果。但当过滤器值包含&这类特殊字符时,请求直接解析失败,报错:

"errors": {
"Invalid request parameters": [
"Invalid OData query '? There is an unterminated string literal at position 37 in 'type_of_secur eq 'Corporate CMOs ?'.'"
]
}

尝试自定义FilterBinder处理特殊字符,但未编码的请求根本无法进入自定义Binder的逻辑,只有使用编码后的字符(如type_of_secur eq 'Corporate CMOs %26 ABS')时,才会触发CustomFilterBinder的BindConstantNode方法:

public class CustomFilterBinder : FilterBinder
{
    public override Expression BindConstantNode(Microsoft.OData.UriParser.ConstantNode constantNode)
    {
        // 自定义逻辑占位
    }
}

核心原因

OData URI中的&属于HTTP URI的保留字符,未编码的情况下,HTTP服务器会将其解析为查询参数的分隔符,导致OData解析器拿到的过滤器字符串被截断,直接判定为未闭合的字符串字面量,报错终止解析,根本无法到达自定义Binder的处理环节。

解决方案

1. 强制对过滤器值中的特殊字符进行URI编码

这是前置必要条件,必须在发起请求前对过滤器中的特殊字符(如&、=、?等)进行URI编码:

  • C#发起请求时,使用Uri.EscapeDataString处理:
    string filterValue = "Ability & ABS";
    string encodedValue = Uri.EscapeDataString(filterValue);
    string filterClause = $"type_of_secur eq '{encodedValue}'";
    // 拼接完整请求URL
    
  • 前端JavaScript中使用encodeURIComponent处理:
    const filterValue = "Ability & ABS";
    const encodedValue = encodeURIComponent(filterValue);
    const filterClause = `type_of_secur eq '${encodedValue}'`;
    

2. 在自定义FilterBinder中处理枚举匹配

当请求携带编码后的参数到达服务器后,OData解析器会自动解码参数值,此时可以在BindConstantNode中处理枚举字符串到数据库整数值的映射:

public class CustomFilterBinder : FilterBinder
{
    public override Expression BindConstantNode(ConstantNode constantNode)
    {
        // 仅处理枚举类型的常量节点
        if (constantNode.Type == typeof(string) && constantNode.Value != null)
        {
            string enumString = constantNode.Value.ToString();
            // 将枚举字符串转换为对应的数据库整数值
            if (Enum.TryParse<SecurityType>(enumString, out var securityType))
            {
                int dbValue = (int)securityType;
                // 返回对应整数值的表达式,后续查询会使用该值匹配数据库列
                return Expression.Constant(dbValue, typeof(int));
            }
        }
        // 其他情况调用基类逻辑
        return base.BindConstantNode(constantNode);
    }
}

3. 配置OData启用严格的URI解析

确保OData配置中启用正确的URI解析规则,避免解析异常:

public static IEdmModel GetEdmModel()
{
    ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
    // 配置实体集等逻辑
    return builder.GetEdmModel();
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers().AddOData(options =>
    {
        options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(null);
        options.AddRouteComponents("v1/odata", GetEdmModel(), services =>
        {
            // 替换为自定义FilterBinder
            services.AddSingleton<FilterBinder, CustomFilterBinder>();
            // 配置URI解析器,启用严格模式
            services.AddSingleton<ODataUriParserSettings>(new ODataUriParserSettings
            {
                EnableCaseInsensitive = true,
                EnableNoDollarQueryOptions = false
            });
        });
    });
}

关键注意事项

  • 永远不要跳过URI编码直接处理特殊字符:未编码的请求在到达OData解析器之前就会被HTTP服务器拆解,导致请求本身无效。
  • 自定义FilterBinder仅能处理已经被OData解析器正确解析的请求,无法修复因URI格式错误导致的解析失败。

内容的提问来源于stack exchange,提问作者Raajesh Ka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 18:56:01