【问题标题】:what is curl doing differently to httr::POST that causes 400 bad request?curl 与导致 400 错误请求的 httr::POST 有何不同?
【发布时间】:2016-12-27 22:13:23
【问题描述】:

我正在尝试从 R 中的 Materials Project web API 查询数据。

文档提供了使用curl 和python 执行的示例查询。我已经复制了下面的curl 命令。

curl -s --header "X-API-KEY: <YOUR-API-KEY>" \
    https://materialsproject.org/rest/v2/query \
    -F criteria='{"elements": {"$in": ["Li", "Na", "K"], "$all": ["O"]}, "nelements": 2}' \
    -F properties='["formula", "formation_energy_per_atom"]'

通过阅读httr quickstart guide,在我看来,我应该能够通过以下方式重现此查询:

library(httr)
POST(url = "https://www.materialsproject.org/rest/v2/query",
     config = add_headers("X-API-KEY" = "<YOUR-API-KEY>",     
     body = list(criteria = "{'elements': {'$in': ['Li', 'Na', 'K'], '$all': ['O']}, 'nelements': 2}",
                 properties = "['formula', 'formation_energy_per_atom']"),
     encode = "multipart",
     verbose())

但是,虽然 curl 命令从 Materials Project 数据库返回 JSON 数据,但我的 R 查询返回 HTTP/1.1 400 BAD REQUEST。 curl 与上述代码中的httr 有何不同?

我尝试将 -v 放在 curl 上并将其与上面的 (verbose()) 输出进行比较,但 curl 没有显示它在多部分表单中的内容。

> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------d2ef2f3982185118
> 
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Date: Tue, 27 Dec 2016 21:18:58 GMT
< Server: Apache/2.2.15 (CentOS)
< Vary: Accept-Encoding,User-Agent
< Connection: close
< Transfer-Encoding: chunked
< Content-Type: application/json

同时httr显示:

-> Content-Type: multipart/form-data; boundary=----------------------------5b4873dbc9cd
-> 
<- HTTP/1.1 100 Continue
>> ------------------------------5b4873dbc9cd
>> Content-Disposition: form-data; name="criteria"
>> 
>> {'elements': {'$in': ['Li', 'Na', 'K'], '$all': ['O']}, 'nelements': 2}
>> ------------------------------5b4873dbc9cd
>> Content-Disposition: form-data; name="properties"
>> 
>> ['formula', 'formation_energy_per_atom']
>> ------------------------------5b4873dbc9cd--

【问题讨论】:

    标签: r curl httr


    【解决方案1】:

    这确实是一个糟糕的、经过深思熟虑且延迟实现的 API。他们似乎喜欢 Python,所以这并不奇怪。

    以下作品:

    library(httr)
    library(jsonlite)
    
    list(
      criteria=toJSON(list(
        elements=list(
          `$in`=c("Li", "Na", "K"),
          `$all`=c("0")
        ),
        nelements=unbox(2)
      )),
      properties=toJSON(c("formula", "formation_energy_per_atom"))
    ) -> params
    
    POST(url="https://www.materialsproject.org/rest/v2/query",
         add_headers(`X-API-KEY`=Sys.getenv("MATERIALS_PROJECT_API_KEY")),
         body=params,
         encode="multipart", verbose()) -> res
    

    下面是 verbose() 的输出来证明这一点:

    -> POST /rest/v2/query HTTP/1.1
    -> Host: www.materialsproject.org
    -> User-Agent: libcurl/7.51.0 r-curl/2.3 httr/1.2.1
    -> Accept-Encoding: gzip, deflate
    -> Accept: application/json, text/xml, application/xml, */*
    -> X-API-KEY: wouldntyouliketoknow
    -> Content-Length: 344
    -> Expect: 100-continue
    -> Content-Type: multipart/form-data; boundary=------------------------34f08173ce0a7818
    -> 
    <- HTTP/1.1 100 Continue
    >> --------------------------34f08173ce0a7818
    >> Content-Disposition: form-data; name="criteria"
    >> 
    >> {"elements":{"$in":["Li","Na","K"],"$all":["0"]},"nelements":2}
    >> --------------------------34f08173ce0a7818
    >> Content-Disposition: form-data; name="properties"
    >> 
    >> ["formula","formation_energy_per_atom"]
    >> --------------------------34f08173ce0a7818--
    
    <- HTTP/1.1 200 OK
    <- Date: Wed, 28 Dec 2016 02:08:08 GMT
    <- Server: Apache/2.2.15 (CentOS)
    <- Vary: Accept-Encoding,User-Agent
    <- Content-Encoding: gzip
    <- Content-Length: 258
    <- Connection: close
    <- Content-Type: application/json
    <- 
    

    超级对查询字符串结构很挑剔。他们真的应该接受一个 JSON 正文并完成它。但是半删减是 python 民间的方式。

    哦,天哪,我刚刚注意到它是一个 CentOS 服务器提供回复。是的。那些人真的很喜欢痛苦。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-13
      • 1970-01-01
      • 1970-01-01
      • 2018-05-27
      • 1970-01-01
      • 1970-01-01
      • 2022-11-11
      • 1970-01-01
      相关资源
      最近更新 更多