含%字符的filter查询参数解析失败问题咨询
看起来你遇到了URL特殊字符(%)导致JSON解析失败的问题,我来帮你拆解下原因和可行的解决办法:
首先明确问题根源:%是URL编码的特殊前缀,比如%23实际是#的URL编码结果。当你直接在filter的value里传入%234时,浏览器或中间件(比如Nginx)会自动把%23解析成#,甚至可能因为编码不完整导致整个filter参数的JSON结构被破坏,自然JSON.parse()就会报错。
下面是几个针对性的解决方案:
1. 前端传参时对%进行二次编码
如果需要在value中传递%字符本身,必须先把%编码为%25(因为%的URL编码就是%25)。比如你原本想传的%234,要改成%25234,最终的请求URL应该是:
hostname.com/posts?filter=[{"property":"title","operator":"ilike","value":"%25234"}]
这样后端接收后经过URL解码,value会还原为%234,整个JSON结构保持完整,JSON.parse()就能正常解析了。
2. 在Nest.js端添加自定义管道处理参数
如果前端没办法修改(或者不想依赖前端处理),可以在Nest.js中写一个自定义管道,专门处理filter参数的解码与解析:
import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common'; @Injectable() export class FilterParsePipe implements PipeTransform { transform(value: any) { try { // 先对参数进行URL解码 const decodedValue = decodeURIComponent(value); // 再解析JSON return JSON.parse(decodedValue); } catch (error) { throw new BadRequestException('Invalid filter parameter format'); } } }
然后在控制器中使用这个管道:
@Get('posts') getPosts(@Query('filter', FilterParsePipe) filter: any[]) { // 这里的filter已经是解析好的数组 return this.postsService.filterPosts(filter); }
这个管道会先对收到的filter参数做URL解码,再解析JSON,能解决大部分编码导致的解析问题。
3. 检查Nginx配置,确保参数完整传递
有时候Nginx的配置会修改查询参数,比如proxy_pass时手动拼接$args、或者rewrite规则可能导致参数被转义/截断。你可以检查Nginx配置,确保参数完整传递给Nest.js:
location / { proxy_pass http://your-nestjs-server; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 确保请求体和头信息完整传递 proxy_pass_request_body on; proxy_pass_request_headers on; }
避免在proxy_pass中手动拼接参数,让Nginx自动传递原始查询参数。
额外提醒:警惕SQL注入风险
既然要允许用户使用ILIKE和通配符,一定要注意SQL注入问题!绝对不要直接把用户传入的value拼接到SQL语句中,应该使用参数化查询。比如用TypeORM的QueryBuilder:
async filterPosts(filter: any[]) { const queryBuilder = this.postRepository.createQueryBuilder('post'); filter.forEach(condition => { if (condition.operator === 'ilike') { // 使用参数绑定避免注入 queryBuilder.andWhere(`post.${condition.property} ILIKE :value`, { value: condition.value }); } else if (condition.operator === '=') { queryBuilder.andWhere(`post.${condition.property} = :value`, { value: condition.value }); } // 其他操作符同理处理 }); return queryBuilder.getMany(); }
这样即使用户传入恶意内容,也不会被执行,能保证数据库安全。
备注:内容来源于stack exchange,提问作者TwittorDrive

