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

Django搜索含百分号参数触发Invalid hex encoding错误的解决咨询

解决Django搜索含百分号内容触发「Invalid hex encoding in query string」异常的方案

问题本质

OAuth库的INVALID_HEX_PATTERN校验会检查查询字符串中%后面是否为合法的十六进制字符(0-9A-F)。当用户搜索含%的内容时,若前端未正确编码(比如直接传递100% natural而非编码后的100%25%20natural),会导致%后面跟非十六进制字符(如空格),触发校验异常。

解决方案

1. 前端强制编码(最彻底)

在前端将搜索关键词用encodeURIComponent()完全编码后再传递,确保所有特殊字符(包括%)都转为合法的URL编码格式:

const searchKeyword = "100% natural";
const encodedKeyword = encodeURIComponent(searchKeyword);
// 拼接URL:/search/?query=${encodedKeyword}

这样能从根源避免非法查询字符串的产生。

2. 后端中间件兜底(处理前端未编码的情况)

由于OAuth中间件会在视图执行前校验请求,需自定义一个优先级高于OAuth中间件的中间件,提前清洗非法的%:

  • 创建中间件文件middleware/query_cleaner.py:
import re
from django.http import HttpRequest

class InvalidQueryCleanerMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # 匹配%后未跟合法十六进制字符的情况
        self.invalid_percent_regex = re.compile(r'%(?![0-9A-Fa-f]{2})')

    def __call__(self, request):
        # 仅处理/search/路径的GET请求
        if request.method == 'GET' and request.path.rstrip('/') == '/search':
            raw_query = request.META.get('QUERY_STRING', '')
            # 将非法%替换为%25(即URL编码后的%)
            cleaned_query = self.invalid_percent_regex.sub('%25', raw_query)
            # 更新请求的查询字符串
            request.META['QUERY_STRING'] = cleaned_query
            # 清除query_params缓存,让Django重新解析
            if hasattr(request, '_query_params'):
                delattr(request, '_query_params')
        
        response = self.get_response(request)
        return response
  • 在settings.py的MIDDLEWARE列表中,将该中间件放在OAuth相关中间件之前:
MIDDLEWARE = [
    # ... 其他基础中间件
    'your_app.middleware.query_cleaner.InvalidQueryCleanerMiddleware',
    # OAuth中间件示例(根据你实际使用的库调整)
    'oauth2_provider.middleware.OAuth2TokenMiddleware',
    # ... 其他后续中间件
]

3. 视图层手动解析(中间件无法调整时的备选)

若无法调整中间件顺序,可直接从请求元数据中获取原始查询字符串,清洗后再解析:

from django.http import QueryDict
import re

def search_system(request):
    raw_query = request.META.get('QUERY_STRING', '')
    # 清洗非法%
    cleaned_query = re.sub(r'%(?![0-9A-Fa-f]{2})', '%25', raw_query)
    # 重新解析为QueryDict
    query_params = QueryDict(cleaned_query, mutable=True)
    query = query_params.get('query', '')
    # QueryDict会自动解码%20为空格,无需手动替换
    # ... 后续搜索逻辑

注意:此方案仅在OAuth中间件不拦截该请求时有效,优先推荐前两种方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 20:01:11