POST 到 API 在 R 中使用 httr 导致错误

POST to API using httr in R results in error

我正在尝试使用 httr 包将数据直接从 API 提取到 R 中。 API 不需要任何身份验证,并接受 JSON 经纬度、海拔、变量集和时间段的字符串来估计任何位置的气候变量。这是我第一次使用 API,但下面的代码是我从各种 Stack Overflow 帖子中拼凑而成的。

library(jsonlite)
library(httr)    
url = "http://apibc.climatewna.com/api/clmApi"
body <- data.frame(lat = c(48.98,50.2), ##two example locations
                   lon = c(-115.02, -120),
                   el = c(1000,100),
                   prd = c("Normal_1961_1990.nrm","Normal_1961_1990.nrm"),
                   varYSM = c("Y","SST"))
requestBody <- toJSON(list("output" = body),auto_unbox = TRUE) ##convert to JSON string

result <- POST("http://apibc.climatewna.com/api/clmApi", ##post to API
               body = requestBody,
               add_headers(`Content-Type`="application/json"))
content(result)

我尝试了各种不同的版本(例如手动编写 JSON 字符串,将正文作为列表放入 POST 和 encode = "json"),并且它始终运行,但内容始终包含以下错误消息:

$Message
[1] "An error has occurred."

$ExceptionMessage
[1] "Object reference not set to an instance of an object."

$ExceptionType
[1] "System.NullReferenceException"

如果我使用 GET 并直接在 URL

中指定变量
url = "http://apibc.climatewna.com/api/clmApi/LatLonEl?lat=48.98&lon=-115.02&el=1000&prd=Normal_1961_1990&varYSM=Y"
result <- GET(url)
content(result)

它产生了正确的输出,但是我一次只能获取一个位置的信息。目前没有关于这个 API 的任何 public 文档,因为它是非常新的,但我在下面附上了使用 JS 解释它的部分的草稿。 非常感谢关于我做错了什么 help/suggestions ! 谢谢!

主要问题是 jQuery.ajax 在将数据发送到 API 之前使用 jQuery.param 对数据进行编码,因此它发送的内容看起来像 [0][lat]=48.98&[0][lon]=-115.02...。我不知道 R 中有与 jQuery.param 类似编码的包,所以我们必须一起破解一些东西。

稍微修改您的示例:

library(httr)
body <- data.frame(lat = c(48.98,50.2), ##two example locations
                   lon = c(-115.02, -120),
                   el = c(1000,100),
                   prd = c("Normal_1961_1990","Normal_1961_1990"),
                   varYSM = c("Y","Y"))

现在,我们进行编码,如下所示:

out <- sapply(1:nrow(body), function(i) {
  paste(c(
    paste0(sprintf("[%d][lat]", i - 1), "=", body$lat[i]),
    paste0(sprintf("[%d][lon]", i - 1), "=", body$lon[i]),
    paste0(sprintf("[%d][el]", i - 1), "=", body$el[i]),
    paste0(sprintf("[%d][prd]", i - 1), "=", body$prd[i]),
    paste0(sprintf("[%d][varYSM]", i - 1), "=", body$varYSM[i])
  ), collapse = "&")
})
out <- paste(out, collapse = "&")

所以现在 out 是 API 喜欢的形式。最后

result <- POST(url = "http://apibc.climatewna.com/api/clmApi", ##post to API
               body = out,
               add_headers(`Content-Type`="application/x-www-form-urlencoded"))

注意到 Content-Type。我们得到

df <- do.call(rbind, lapply(content(result), as.data.frame, stringsAsFactors = FALSE))
str(df)
# 'data.frame': 2 obs. of  29 variables:
#  $ lat    : chr  "48.98" "50.2"
#  $ lon    : chr  "-115.02" "-120"
#  $ elev   : chr  "1000" "100"
#  $ prd    : chr  "Normal_1961_1990" "Normal_1961_1990"
#  $ varYSM : chr  "Y" "Y"
#  $ MAT    : chr  "5.2" "8"
#  $ MWMT   : chr  "16.9" "20.2"
#  $ MCMT   : chr  "-6.7" "-5.6"
#  $ TD     : chr  "23.6" "25.7"
#  $ MAP    : chr  "617" "228"
#  $ MSP    : chr  "269" "155"
#  $ AHM    : chr  "24.7" "79.1"
#  $ SHM    : chr  "62.9" "130.3"
#  $ DD_0   : chr  "690" "519"
#  $ DD5    : chr  "1505" "2131"
#  $ DD_18  : chr  "4684" "3818"
#  $ DD18   : chr  "60" "209"
#  $ NFFD   : chr  "165" "204"
#  $ bFFP   : chr  "150" "134"
#  $ eFFP   : chr  "252" "254"
#  $ FFP    : chr  "101" "120"
#  $ PAS    : chr  "194" "34"
#  $ EMT    : chr  "-36.3" "-32.7"
#  $ EXT    : chr  "37.1" "41.2"
#  $ Eref   : chr  "14.7" "13.6"
#  $ CMD    : chr  "721" "862"
#  $ MAR    : chr  "347" "679"
#  $ RH     : chr  "57" "57"
#  $ Version: chr  "ClimateBC_API_v5.51" "ClimateBC_API_v5.51"