Android使用Retrofit的@Query注解传递过滤条件无响应如何解决
问题根因及解决方案
- Retrofit的Query参数自动URL编码问题:Retrofit默认会对
@Query注解传入的参数值做URL编码,你传入的AND YEAR(BillingDate)>=2019 AND YEAR(BillingDate)<=2022里的空格、>、<等符号会被编码为%20、%3E、%3C这类格式,PHP端$_GET拿到编码后的字符串直接拼接进SQL后,完全不符合SQL语法,会导致SQL执行报错、甚至数据库卡死无返回,前端表现就是请求无响应。而你直接在浏览器地址栏传参时,部分场景下浏览器不会对特殊符号做强制编码,或者PHP侧自动做了解码处理,所以能正常返回。 - 特殊字符转义+SQL注入风险:直接把前端传入的参数拼接SQL属于高危SQL注入漏洞,同时如果PHP侧开启了特殊字符自动转义(比如旧版本的
magic_quotes_gpc配置、或者框架自动做了addslashes处理),参数里的引号、括号等字符会被加转义符,进一步破坏SQL语法导致执行失败。 - SQL执行效率问题:添加日期过滤条件后,如果
BillingDate字段没有加索引,或者YEAR()函数包裹索引字段导致索引失效,会触发全表扫描,数据量较大时SQL执行时间远超Retrofit设置的超时阈值,也会表现为请求无响应。
修复方案
- 不要直接把过滤条件作为参数传递:后端提前定义好可传入的过滤规则,比如前端只传起止年份
start_year、end_year,后端接收到参数后自行拼接SQL的过滤条件,从根源避免编码问题和SQL注入风险。 - 必须使用参数化查询(预处理语句)执行SQL,不要直接拼接用户传入的任何参数。
- 给
BillingDate字段添加索引,调整日期过滤写法为BillingDate BETWEEN '2019-01-01' AND '2022-12-31'避免函数包裹索引字段,提升查询效率。 - 临时验证的话可以给
@Query注解添加encoded = true属性,即@Query(value = "mselectperiod", encoded = true),告知Retrofit不要对该参数做自动编码,验证是否是编码问题导致的故障,该方案仅用于测试,不可线上使用,依然存在SQL注入风险。
内容的提问来源于stack exchange,提问作者Anthony Mwangi
相关产品推荐
相关产品推荐

