如何在使用jQuery $.ajax()时通过请求主体发送数据的GET请求?

81
我要调用的服务API需要在请求体中发送数据的特定GET方法。请求体中所需的数据是由连字符分隔的ID列表,可能非常大,因此必须将其发送到请求体中,否则它很可能会在浏览器/代理/ Web服务器等链路中出现问题。请注意,我无法控制服务或API,因此请不要建议更改它。我正在使用以下jQuery代码,但是在fiddler中观察请求/响应时,我可以看到我发送的“数据”始终被转换并附加到查询字符串上,尽管我将“processData”选项设置为false...
$.ajax({
   url: "htttp://api.com/entity/list($body)",
   type: "GET",
   data: "id1-id2-id3",
   contentType: "text/plain",
   dataType: "json",
   processData: false, // avoid the data being parsed to query string params
   success: onSuccess,
   error: onError
});

有人知道如何强制将“data”值发送到请求的正文中吗?


1
“在正文中”?我能想到的唯一与您所询问的事件有点相似的事情是POST请求... (POST /path HTTP/1.0\r\n<headers>\r\n\r\n<post_vars>) - Brad Christie
3
如果API是通用的,并遵循HTTP规范,我认为即使你设法这样做,它也不会接受在GET请求的正文中发送的参数。你确定吗?这是一个有用的帖子:https://dev59.com/53NA5IYBdhLWcg3wZ85S - Niks
基本上这是不可能的,因为正如人们所说,它并不是HTTP规范的一部分。最终我们不得不将ID放在查询字符串中,并浏览结果,以便它不会变得太长。我会接受已经给出的答案,谢谢EndangerredMassa。 - Oliver Pearmain
1
虽然这不是标准,但在某些情况下很有用。当发送utf-8编码的GET请求体或传递大型json请求体时,就可以使用它。Elastic Search广泛使用这种风格。 - sandstrom
发送GET请求体是否比发送POST请求体不安全? - user1637000
@user1637000 就安全性而言,这两种方式是完全相同的。顺便说一句,在请求正文中传递参数并不比在查询字符串中更安全。 - challet
4个回答

72

一般来说,系统不会使用GET请求,因此很难让您的库跟随。事实上,规范指出:“如果请求方法与GET或HEAD完全匹配,则视为数据为空。”所以,除非您使用的浏览器不遵守规范的这部分内容,否则我认为您运气不好。

您可以在自己的服务器上设置一个端点,用于POST ajax请求,然后在服务器代码中将其重定向为带有正文的GET请求。

如果您并非绝对需要具有正文数据的GET请求,则有两种选择:

带有数据的POST: 这可能是您想要的。如果您传递数据,那可能意味着您正在修改某个模型或在服务器上执行某些操作。这些类型的操作通常使用POST请求完成。

带有查询字符串数据的GET: 您可以将数据转换为查询字符串参数,并以此方式将其传递给服务器。

url: 'somesite.com/models/thing?ids=1,2,3'

7
虽然我很感谢你的建议,但这两个建议都涉及更改服务,而我已经说过这是不可能的。 - Oliver Pearmain
4
感谢您提供了额外的建议,建议添加一个代理程序将POST请求转换为带有正文的GET请求。我尝试在.NET中实现这个功能,但是它抛出了一个"ProtocolViolationException"异常,错误信息为"Cannot send a content-body with this verb",明确强调带有正文的GET请求不是被支持的使用案例。 - Oliver Pearmain
31
Elasticsearch广泛使用GET与请求体。 - Andrey
2
我甚至不知道为什么人们坚持认为GET方法没有请求体数据。当你尝试使用POST方法并带有请求体(例如用于过滤)来“获取”信息时,当然会更有意义,只是因为有人在互联网上说你不应该在GET方法中传递请求体数据。如果您需要获取信息并传递其他数据(例如搜索查询),请继续传递它。 - JaktensTid
2
“可能意味着您正在修改某个模型或在服务器上执行某些操作。”-- 可能是这样,但并非总是如此。我有一个批量GET请求。如果我将所有内容都发送到查询中,那么它会太长。我的唯一选择是更改服务器配置或假装这是POST请求的适当情况。咕哝。 - Mattias Martens
显示剩余7条评论

5
我们通常知道,根据HTTP标准发送数据时,我们一般使用POST请求。但是如果您真的想在您的场景中使用Get来发送数据,我建议您使用查询字符串或查询参数。
1. 使用查询字符串的GET请求如下: {{url}}admin/recordings/some_id 这里的some_id是必需的参数,可以在服务器端使用req.params.some_id。
2. 使用查询字符串的GET请求如下: {{url}}admin/recordings?durationExact=34&isFavourite=true 这里的durationExact和isFavourite是可选的字符串,可以在服务器端使用req.query.durationExact和req.query.isFavourite。
3. GET发送数组的示例如下: {{url}}admin/recordings/sessions/?os["Windows","Linux","Macintosh"] 您可以像这样在服务器端访问这些数组值。
let osValues = JSON.parse(req.query.os);
        if(osValues.length > 0)
        {
            for (let i=0; i<osValues.length; i++)
            {
                console.log(osValues[i])
                //do whatever you want to do here
            }
        }

-2

以防万一还有人遇到这个问题:

在任何请求中都有一个body query对象。您不需要自己解析它。

例如,如果您想从客户端使用GET发送accessToken,可以像这样操作:

const request = require('superagent');

request.get(`http://localhost:3000/download?accessToken=${accessToken}`).end((err, res) => {
  if (err) throw new Error(err);
  console.log(res);
});

服务器请求对象看起来像这样:{request: { ... query: { accessToken: abcfed } ... } }

OP 正在询问 request.body,不是 request.query。你提到了 POST,但你的代码示例中仍在使用 request.get() - Danosaure
是的,我明白。但是查询和正文都可以用来获得相同的结果。我想他很容易考虑将请求查询作为一种替代方法。 - Neskews
用户可以在浏览器的地址栏中看到request.query。有时候我们想要隐藏传输的数据,因此我们仍然更喜欢使用POST请求。 - profimedica

-2

你知道吗,我有一种不太标准的方法来解决这个问题。我通常使用nextjs。如果可能的话,我喜欢将事物变得restful。如果我需要进行get请求,我会使用post,并在body中添加一个子方法参数,该参数为GET。此时,我的服务器端会处理它。我知道从技术上讲它仍然是一个post方法,但这使意图清晰,而且我不需要添加任何查询参数。然后,get方法使用post方法中提供的数据处理get请求。希望这可以帮助到你。虽然这是一个绕过正确协议的小技巧,但这意味着没有疯狂的解决方案,服务器端的代码也可以处理它而没有任何问题。服务器端的第一件事就是if(subMethod === "GET"){|做你需要做的|}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接