【问题标题】:How to set the body of a POST request using Ruby Mechanize?如何使用 Ruby Mechanize 设置 POST 请求的主体?
【发布时间】:2014-08-15 15:33:27
【问题描述】:

如何使用 Ruby Mechanize gem 设置 POST 请求的主体。我知道你能做到

mechanize.post(url, query, headers)

但我想使用 JSON 字符串设置 POST 请求的正文。那可能吗?所以,类似于 jQuery:

$.ajax({
    type: 'POST',
    url:  'myurl',
    data: "{'key1':'value1','key2':'value2'}",
    ...
});

【问题讨论】:

标签: ruby mechanize-ruby


【解决方案1】:

我不太喜欢您在评论中链接到的答案,因为它使用了一个 rails 方法的 to_json(),并且您问题的标签并不表明您的问题与 rails 相关。无论如何,我认为答案需要一些讨论。

机械化方法如下:

Mechanize#post(url, query, headers)

...您的既定目标是:

我想设置 POST 请求的正文

Mechanize#post() 允许您将请求的正文设置为您想要的任何内容,但您还必须考虑以下问题:

What is the server side expecting?  

您提供了一个 jquery ajax() 请求示例,说明您想要做什么。 jquery 在发送 ajax() 请求时使用以下默认 Content-Type 标头:

application/x-www-form-urlencoded; charset=UTF-8

这告诉服务器发布请求的主体将被写入特定的密码。好吧,这不是什么秘密。它看起来像这样:

name1=val1&name2=val2

那个密码的名字是x-www-form-urlencoded。因为在 Content-Type 标头中为服务器提供了密码的名称,所以服务器知道如何读取 post 请求的正文。

在 Mechanize#post() 方法中,第二个参数是“查询”,机械化文档对查询参数是这样说的:

查询由字符串

指定

散列表示的键值对列表,或

数组数组

http://rubydoc.info/gems/mechanize/Mechanize#post-instance_method

如果您想在 Mechanize#post() 请求的正文中使用名为 x-www-form-urlencoded 的密码,则可以提供带有名称/值对的哈希,例如

my_hash = {
  'data' => '{"key1":"value1","key2":"value2"}'
}

然后你像这样调用 Mechanize#post():

my_agent.post(
  'http://target_site.com', 
  my_hash, 
  {'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8'},
)

然后 Mechanize 将使用名为 x-www-form-urlencoded 的密码将“查询”哈希转换为字符串,并将该字符串插入到发布请求的正文中。在服务器端,接收到 post 请求的应用程序可以通过以下方式检索 json 字符串:

json_str = post_variables['data']   

您应该知道,还有其他密码可用于发布请求的正文。其中一个叫做json,它是一个使用javascript语法格式化的字符串,例如:

  '{
    "id": 1,
    "name": "A green door",
    "price": 12.50,
    "tags": ["home", "green"]
  }'

请注意 json 格式中没有“=”符号或“&”符号——就像 x-www-form-urlencoded 格式一样,所以 json 密码与 x-www-form-urlencoded 密码有很大不同.

如果你想在你的 post 请求正文中使用 json 密码,你需要在调用 Mechanize#post(url, query, headers) 时更改两件事:

  1. 为“查询”参数提供一个字符串。
  2. 告诉服务器 post 请求的正文使用 json 密码。

像这样:

json_str = '{"key1":"value1","key2":"value2"}'

my_agent.post(
  'http://target_site.com', 
  json_str, 
  {'Content-Type' => 'application/json'},
)

当您为查询参数传递一个字符串参数时,Mechanize 在将字符串插入到 post 请求的正文之前不会对字符串进行任何处理。在服务器端,接收到 post 请求的应用程序可以通过执行以下操作来检索 json 字符串:

json_str = request.body.read
#Then probably:
hash = JSON.parse(json_str)

一个问题是服务器可以忽略 Content-Type 标头并尝试使用它已经确定的密码来读取发布请求的正文。如果您的 post 请求正文没有写入服务器期望的密码,那么您将收到错误。

请注意,您发布的“数据”字符串不是有效的 json,因为它在属性和值周围使用单引号。

【讨论】:

  • 我的 json 字符串非常小而且很扁平,所以我只是手动生成了它,但你说得对,我的问题更笼统。另外,关于 json 无效的好处,我什至没有意识到,因为我发送它的服务器一直在接受它。
  • @RTF,我猜您实际上是在查看您在评论中链接到的问题中未接受的答案。显然,这是另一种设置 post 请求正文的方式。
  • @RTF,在您的 ajax() 示例中,jquery 文档说如果 'data' 是一个字符串(如您指定的那样),那么 jquery 不会 处理将字符串转换为x-www-form-urlencoded 格式,所以我的答案的部分前提就消失了。我猜是因为您的 jquery 示例没有指定 contentType 属性,所以您最终会得到默认的 Content-Type 标头 application/x-www-form-urlencoded 但帖子正文将采用 json 格式,这可能会搞砸服务器。无论如何,您的 jquery 示例充分展示了您想要做什么——我只是误解了它。
  • ...请注意,jquery ajax() 'data' 属性的工作方式类似于 Mechanize#post() 'query' 参数:如果您提供对象/哈希,则转换对象/哈希x-www-urlencoded 格式的字符串;如果你提供了一个字符串,它会被原封不动地插入到请求的正文中。
猜你喜欢
  • 2011-09-07
  • 1970-01-01
  • 1970-01-01
  • 2018-01-30
  • 1970-01-01
  • 1970-01-01
  • 2021-01-25
  • 2014-11-09
  • 2018-01-20
相关资源
最近更新 更多