更新httr 1.4.7与curl 5.0.2后GET请求出现401认证异常求助
问题背景
自2019年正常运行的R脚本,使用httr包处理GET/POST请求。更新httr至1.4.7(配套curl 5.0.2)后,GET请求返回401未授权错误,但POST请求仍正常工作。已验证相同的URL、请求头和凭证在Python requests、命令行curl、R的system(curl)命令中均可正常运行,仅httr的GET代码失效。脚本需部署至Posit Connect服务器,需排查curl/httr更新导致的问题并修复。
涉及代码如下:
POST认证请求
r = POST( url = paste(apiUrl, "auth/login", sep = ""), use_proxy("http://proxy-xyz.pqr.com", 9090, "pxy-uid", "pxy-pwd"), add_headers(Accept = "application/vnd.seeq.v1+json", `Content-Type` = "application/vnd.seeq.v1+json"), body = paste('{"authProviderClass":"Auth", "authProviderId":"Vendor", "username":"uid", "password":"pwd"}',sep = "") ) token <<- r[["headers"]][["x-sq-auth"]]
GET数据请求
r = GET(url = "https://myurl", use_proxy("https://proxy-xyz.pqur.com", 9090, "pxy-uid", "pxy-pwd"), query = list(start = start, end = end, period = period), add_headers(Accept = "application/vnd.seeq.v1+json", `x-sq-auth` = token #`x-sq-csrf` = token ) ) fromJSON(content(r, as="text", encoding="UTF-8"))[["samples"]]
可能的问题点及修复方案
1. 代理URL协议与地址不一致
观察代码发现POST与GET请求的代理配置存在两处明显差异:
- 协议:POST使用
http://代理,GET误用https://(多数企业代理为HTTP协议,除非明确配置了HTTPS代理) - 域名:
proxy-xyz.pqr.comvsproxy-xyz.pqur.com(疑似笔误)
修复操作:
将GET请求的代理地址统一为POST使用的配置:
r = GET(url = "https://myurl", use_proxy("http://proxy-xyz.pqr.com", 9090, "pxy-uid", "pxy-pwd"), query = list(start = start, end = end, period = period), add_headers(Accept = "application/vnd.seeq.v1+json", `x-sq-auth` = token) )
2. httr新版本代理认证逻辑变化
httr 1.4.x与curl 5.x的配合中,use_proxy函数的代理认证传递逻辑可能发生了变化。尝试改用config函数直接配置代理参数,确保认证信息正确传递:
修复操作:
替换use_proxy为config配置:
# 定义全局代理配置 proxy_config <- config( proxy_url = "http://proxy-xyz.pqr.com", proxy_port = 9090, proxy_userpwd = paste0("pxy-uid:", "pxy-pwd") ) # GET请求调用该配置 r = GET(url = "https://myurl", config = proxy_config, query = list(start = start, end = end, period = period), add_headers(Accept = "application/vnd.seeq.v1+json", `x-sq-auth` = token) )
3. 验证请求实际发送细节
使用verbose()函数查看GET请求的完整发送日志,对比命令行curl的请求,确认x-sq-auth头、代理信息、query参数是否正确传递:
操作方法:
在GET请求中添加verbose()参数:
r = GET(url = "https://myurl", use_proxy("http://proxy-xyz.pqr.com", 9090, "pxy-uid", "pxy-pwd"), query = list(start = start, end = end, period = period), add_headers(Accept = "application/vnd.seeq.v1+json", `x-sq-auth` = token), verbose() )
重点检查输出内容:
- Request Headers是否包含
x-sq-auth: [你的token] - Proxy是否正确使用指定的地址和端口
- Query参数是否完成正确编码
4. 迁移至httr2包
httr已进入维护状态,httr2作为其继任者,对新curl版本的兼容性更好,API设计更严谨。尝试迁移到httr2:
示例代码:
# 安装httr2(若未安装) # install.packages("httr2") library(httr2) # POST认证请求 r <- request(paste(apiUrl, "auth/login", sep = "")) |> req_proxy(url = "http://proxy-xyz.pqr.com", port = 9090, username = "pxy-uid", password = "pxy-pwd") |> req_headers( Accept = "application/vnd.seeq.v1+json", `Content-Type` = "application/vnd.seeq.v1+json" ) |> req_body_json(list( authProviderClass = "Auth", authProviderId = "Vendor", username = "uid", password = "pwd" )) |> req_perform() token <- resp_header(r, "x-sq-auth") # GET数据请求 r <- request("https://myurl") |> req_proxy(url = "http://proxy-xyz.pqr.com", port = 9090, username = "pxy-uid", password = "pxy-pwd") |> req_headers( Accept = "application/vnd.seeq.v1+json", `x-sq-auth` = token ) |> req_url_query(start = start, end = end, period = period) |> req_perform() fromJSON(resp_body_string(r))[["samples"]]
5. 配置Posit Connect全局代理环境变量
若上述方案无效,需确认Posit Connect服务器的全局代理配置是否与本地一致。可在脚本开头显式设置环境变量:
Sys.setenv( http_proxy = "http://pxy-uid:pxy-pwd@proxy-xyz.pqr.com:9090", https_proxy = "http://pxy-uid:pxy-pwd@proxy-xyz.pqr.com:9090" )
设置后,httr会自动使用该代理,无需在每个请求中重复指定use_proxy。
内容的提问来源于stack exchange,提问作者ok1more

