如何仅对URL中部分查询参数应用URL编码规则适配人口普查API?
针对Census Microdata API编码问题的解决方案
1. 避免'+'被转义的核心思路
Census的汇总API采用非标准编码规则,需要对查询参数做分类处理:
- 带
+的参数键(如col+AGEGROUP、recode+AGEGROUP):不做URL编码,保留原生+ - 参数值以及无特殊字符的参数键:使用标准URL编码,保证特殊字符不会引发解析错误
Drakma专属解决方案
你不需要从Drakma切换到Dex,只需在调用drakma:http-request时添加:preserve-uri t参数,传入你手动拼好的完整URL字符串即可,Drakma会完全保留URI内容,不会自动将+转义为%2B:
(drakma:http-request "完整拼接好的符合API要求的URL字符串" :preserve-uri t :method :get)
Dexador通用解决方案
首先纠正用法:Dexador支持直接传递查询参数
使用:query关键字参数传入键值对列表即可,和Drakma用法一致:
(dex:get "https://api.census.gov/data/2019/acs/acs5/pums" :query '(("get" . "NP") ("for" . "state:01")))
适配非标准编码的URL构造方案
封装专用构造函数,仅对需要编码的部分做处理,其余内容保留原生格式,既避免+被转义,也保证编码健壮性:
(ql:quickload '(:quri :str)) (defun build-census-pums-url (tabulate-json fixed-plus-params other-params) "构造符合Census编码要求的请求URL tabulate-json: 未编码的汇总命令JSON字符串 fixed-plus-params: 带+的参数列表,如 '(\"col+AGEGROUP\" \"recode+AGEGROUP\") other-params: 普通查询参数键值对,如 '((\"for\" . \"state:01\"))" (let* ((base "https://api.census.gov/data/2019/acs/acs5/pums") ;; 单独编码汇总命令的JSON内容 (encoded-json (quri:url-encode tabulate-json)) ;; 拼接tabulate参数和带+的固定参数,不编码+ (tabulate-part (format nil "tabulate=weight(PWGTP)&~a=\"~a\"" (str:join "&" fixed-plus-params) encoded-json)) ;; 编码普通参数 (other-part (str:join "&" (loop for (k . v) in other-params collect (format nil "~a=~a" (quri:url-encode k) (quri:url-encode v))))) ;; 拼接完整查询串 (query-str (if (str:empty? other-part) tabulate-part (str:join "&" (list tabulate-part other-part))))) (format nil "~a?~a" base query-str))) ;; 调用示例 (defvar *my-url* (build-census-pums-url "{\"b\":AGEP,\"d\":[[0,1,2,3],[{\"mn\":4,\"mx\":99}]]}" '("col+AGEGROUP" "recode+AGEGROUP") '(("for" . "state:01")))) ;; 传入Dex请求,无需额外编码 (dex:get *my-url*)
2. 方案优势
- 仅对
tabulate参数的JSON内容和普通参数做标准URL编码,符合API要求 - 带
+的参数键完全保留原生格式,不会被转义为%2B - 所有需要编码的部分都使用成熟的Quri库处理,避免手动编码的遗漏问题,健壮性远高于全手动拼接
内容的提问来源于stack exchange,提问作者Halbert
相关产品推荐
相关产品推荐

