使用JSON格式的主体内容参数调用HTTP GET请求

6

我可以帮忙翻译如何使用JSON参数在内容体中调用HTTP GET请求。

我尝试了以下代码:

HttpWebRequest.WebRequest.Create(_uri);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
httpWebRequest.Headers.Add("X-AUTH-TOKEN", _apiKey);

using(var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) {
  string _json = "\"{\"filter\": {\"relation\": \"equals\", \"attribute\": \"state\", \"value\": \"CA\"  },  \"insights\": {\"field\": \"family.behaviors\",  \"calculations\": [\"fill_count\"]}}";

  streamWriter.Write(_json);
  streamWriter.Flush();
  streamWriter.Close();
}

var httpResponse = (HttpWebResponse) httpWebRequest.GetResponse();
using(var streamReader = new StreamReader(httpResponse.GetResponseStream())) {
  var result = streamReader.ReadToEnd();
}

但是它会抛出一个异常:

"使用此动词类型无法发送内容主体。"


如果您想保存数据,请使用POST方法;如果您想更新数据,请使用PUT方法,这是在httpWebRequest.Method中的设置。 - Rashedul.Rubel
您可以通过将方法设置为POST来勾选它,然后编写正文,然后将方法更改回GET。这样做是有效的,但我不知道它是否会在执行这种“肮脏”的操作后发送正文。您可能需要数据包捕获/访问服务器/测试结果来真正弄清楚这一点。 - Max
使用POST作为方法类型。如果您使用HttpClient,那将更好。因为它可以直接提供异步方法,并且易于使用。 - R.Sarkar
可能是重复的问题,参见HttpClient是否可以在GET请求中发送内容或主体? - Ian Kemp
4个回答

6
如果您使用.NET Core,新的HttpClient可以处理此问题。否则,您可以使用System.Net.Http.WinHttpHandler软件包,但它有大量依赖关系。请参见答案 https://dev59.com/01cQ5IYBdhLWcg3wCvY4#47902348 了解如何使用这两个选项。
我不能使用.NET Core,也不想安装System.Net.Http.WinHttpHandler。我通过反射解决了这个问题,欺骗WebRequest,使其认为使用GET请求发送正文是合法的(这是根据最新的RFC)。我的做法是将HTTP动词“GET”的ContentBodyNotAllowed设置为false。
var request = WebRequest.Create(requestUri);

request.ContentType = "application/json";
request.Method = "GET";

var type = request.GetType();
var currentMethod = type.GetProperty("CurrentMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(request);

var methodType = currentMethod.GetType();
methodType.GetField("ContentBodyNotAllowed", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(currentMethod, false);

using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
    streamWriter.Write("<Json string here>");
}

var response = (HttpWebResponse)request.GetResponse();

请注意,然而属性ContentBodyNotAllowed属于静态字段,因此当其值更改时,在程序的其余部分仍然有效。对于我的目的来说这不是问题。

作为一个了解系统集成和代理服务器的困难以及第三方服务器将这类交易标记为畸形请求的人,我想感谢您的发现。如果我的微服务彼此交流且我想在GET请求中添加body...那么应该是允许的。经过测试,它可以完美地工作。 - Suamere
这属于“肮脏的黑客”类别,但它能用!谢谢! - Mad Scientist

1

0

只能使用GET方法来获取数据。

如果您需要指定参数,请将其包含在URL中。
或者,如果使用POST或PUT,则可以发送JSON BODY。

HTTP请求方法

HTTP定义了一组请求方法,用于指示要对给定资源执行的所需操作。虽然它们也可以是名词,但这些请求方法有时被称为HTTP动词。每个方法实现不同的语义,但它们之间共享某些常见特性:例如,请求方法可以是安全的、幂等的或可缓存的。

  • GET
    GET方法请求获取指定资源的表示形式。使用GET的请求应该只检索数据。
  • HEAD
    HEAD方法要求一个响应与GET请求完全相同,但没有响应正文。
  • POST
    POST方法用于向指定资源提交实体,通常会导致服务器上的状态变化或副作用。
  • PUT
    PUT方法使用请求负载替换目标资源的所有当前表示。

此外:

我找到了这个。已经进行了长时间的讨论。
HTTP GET with request body

这意味着可以在GET请求中发送BODY,但是发送负载体可能会导致某些现有实现拒绝请求(例如路由中间的代理)。

请务必仔细阅读本文,因为还有许多其他要注意的地方。


顺便说一下,似乎你可以使用cURL命令的-i选项发送带有正文的GET请求。

Curl带有json参数的GET请求


0

虽然在技术上允许使用Get请求发送正文,但微软已经决定不允许这样做。

这可以在HttpWebRequest源代码中看到:

if (onRequestStream) {
// prevent someone from getting a request stream, if the protocol verb/method doesn't support it
    throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget));
}

所以你需要将动词更改为PutPost,或者采用其他解决方法


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