【问题标题】:C# HTTP Body with GET method带有 GET 方法的 C# HTTP 正文
【发布时间】:2012-08-17 21:08:13
【问题描述】:

我使用的 API 要求我将方法设置为 GET 并包含消息正文。但是,当我尝试执行此操作时,出现以下错误:“无法发送具有此动词类型的内容主体”。我读到 HttpWebRequest 类不支持这一点,这是异常的原因。有解决办法吗?

这是我当前的代码:数据是一个 json 字符串,编码为字节数组

HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "GET";
request.ContentType = "application/json";
request.ContentLength = data.Length;
using (Stream requestStream = request.GetRequestStream()) {
    requestStream.Write(data.ToArray(), 0, (int)data.Length);
}

这是我要模拟的 PHP 代码

<?php
$data = array("id" => "1234");
$data_string = json_encode($data);
$ch = curl_init('url');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'Content-Length: ' . strlen($data_string))
);
$result = curl_exec($ch);
var_dump($result);
?>

谢谢,

【问题讨论】:

标签: c# .net http


【解决方案1】:

什么叫做主动违背 REST 的 API? “急速”? “不安”?

幸运的是,他们的服务并不关心动词是什么,而 PHP 代码只是碰巧使用 GET 并遇到了服务器没有阻止它的错误,这是一个非常小的错误,只要它的行为正确,并且可以使用 POST。

如果做不到这一点,最好的办法是看看他们是否有替代方法(如果它是一个自然适合 GET 的读取请求)接受 URI 中的参数,并且可能根据 RFC 2616 使用适当的标头,或者可以通过 POST、GET 等方式接受一些东西。

如果这不起作用,您将不得不在 TcpClient 之上构建一个 HTTP 客户端。这将是非常可怕的。

【讨论】:

  • 我开始认为我必须走那条路。但我会尝试询问他们是否可以接受 URI 中的参数。这对我来说似乎很简单。
  • 好吧,我永远不会抱怨我不得不再次忍受的违反 REST 的行为。不,那是谎言,我会一直抱怨他们,但坚持使用 GET 的身体是我见过的最糟糕的事情。 (您已经确认它拒绝使用 POST 处理相同的数据,是吗?)
  • 是的,因为 POST 用于执行实体的更新,它只返回操作的状态,如果操作失败则作为 JSON 对象返回消息。我将尝试说服 API 开发人员修改他们的 GET 方法,否则我将不得不使用 TcpClient 创建一个单独的调用。谢谢。
  • @JonHanna - 我认为在 GET 方法中发布正文也很愚蠢;不幸的是,我认为一些高级 Elasticsearch 6.6 _search 示例当前在使用 GET 方法时会传递一个正文。我需要在 ASP.NET 中模拟这些示例。 HttpWebRequest 不允许我这样做,而且我无法轻松访问 CURL:elastic.co/guide/en/elasticsearch/reference/current/…
  • 我测试了 HttpWebRequest、WebRequest 和 HttpClient。如果您在 GET 请求中包含内容正文,它们都会返回异常。 C# 不是这个问题的朋友。我不知道你的系统是如何构建的。是否可以将您的 api 请求移至网站并使用 javascript 发出请求? Javascript 将允许您在 GET 请求中包含内容主体。
【解决方案2】:

完全有可能,但你必须使用较新的 HttpClient 类:https://stackoverflow.com/a/47902348/70345

【讨论】:

  • -1 我试过了。基础 > System.Net.ProtocolViolationException > 基础 > System.InvalidOperationException > “方法为:GET 时无法发送数据”
  • @minnow 感谢您提醒我这一点 - 我在实际测试此代码后不久发布了答案,所以我忘记了我只能让它与 Core 一起工作 - 我有对其进行了修改以注意这一点。
  • @LasseVågsætherKarlsen HTTP 规范中没有任何内容明确禁止在使用无主体动词时发送带有主体的请求。当然,在某些情况下,IMO 这样做是有效的:特别是,如果您的请求非常大(太大而无法对 URL 中的所有参数进行编码) - 例如,Elasticsearch 会这样做。现在,您可能会说“在这种情况下,使用 POST”,但在语义上(至少从 RESTful 的角度来看),POST 是更新资源,而 GET 是检索资源。无论如何 - 我不想在 cmets 中陷入语义/宗教战争。
  • GET 记录在HTTP specification 中以检索“由请求URI 标识”的信息,其中不包括正文。我了解并知道很多服务“滥用”(我认为,无需对此作出回应)GET 请求并发送大量数据,但实际上不在规范中。显然它可以在技术上完成,我已经看到很多使用它的服务,但它不符合规范。但是,是的,没有必要为此创建一个大线程,无论如何它都会以意见的形式结束:)
  • 建议不要这样做,它不是 SPEC 的一部分。这就是 .net 核心实现它的原因,因为有需要并且在语义上发送 post 请求来检索数据是没有意义的。单声道运行时并没有那么清楚,这是一个偏好问题。
【解决方案3】:

不建议使用 GET 请求发送内容。有关详细信息,请参阅此帖子:HTTP GET with request body

还有this is what Roy Fielding has to say about the topic

【讨论】:

  • 谢谢。我明白这一点,但它不在我的掌控之中。这是我需要使用的第三方 API。
  • Ehm,你知道这就是 ElasticSearch 的 REST API 的工作原理吗?发送复杂查询需要请求正文和 GET 请求。从概念上讲,这与 REST 的工作方式非常相似。任何其他动词都是错误的,并且您不能总是将复杂的查询压缩到 URL 中。我很惊讶 HttpWebRequest 对象无法处理。
猜你喜欢
  • 1970-01-01
  • 2020-11-21
  • 1970-01-01
  • 2015-07-02
  • 1970-01-01
  • 2019-10-25
  • 1970-01-01
  • 2019-09-03
相关资源
最近更新 更多