gpt4 book ai didi

rest - TREST请求 : Is it possible to use custom media types in a POST request?

转载 作者:可可西里 更新时间:2023-11-01 16:31:42 26 4
gpt4 key购买 nike

我们有一个 API 需要我们自己的供应商特定内容类型,例如 application/vnd.xxxx.custom.custom-data+json 但是查看 REST.Client 的源代码似乎始终默认为 REST.Types 中的 ContentTypes 之一,例如,在我的正文请求中分配 ctNone 时,它将默认为 ctAPPLICATION_X_WWW_FORM_URLENCODED

我已尝试将内容类型直接分配给 TRESTClient.ContentType 属性,但它会被 TRESTRequest.ContentType 值覆盖。我还在 TRESTRequest 上添加了自定义内容类型作为参数,它确实被识别但仍然在末尾附加 ctAPPLICATION_X_WWW_FORM_URLENCODED 导致无效的 MIME 类型异常。

begin
APIClient := TRESTClient.Create(API_URL);
APIRequest := TRESTRequest.Create(nil);

try
JsonToSend := TStringStream.Create(strJson, TEncoding.UTF8);
APIClient.Accept := 'application/vnd.xxxx.custom.custom-data+json';
// Below line gets overwritten
APIClient.ContentType := 'application/vnd.xxxx.custom.custom-data+json';
APIRequest.Client := APIClient;
APIRequest.Resource := 'ENDPOINT_URL';
APIRequest.Accept := 'application/vnd.xxxx.custom.custom-data+json';

APIRequest.AddParameter(
'Content-Type',
'application/vnd.xxxx.custom.custom-data+json',
pkHTTPHEADER,
[poDoNotEncode]
); // This includes the custom CT in the request but appends the preset one as well so in this case ctAPPLICATION_X_WWW_FORM_URLENCODED when ctNone is set

APIRequest.AddBody(JsonToSend, ctNone);
APIRequest.Method := rmPost;
try
APIRequest.Execute;
except
on E: Exception do
ShowMessage('Error on request: '#13#10 + e.Message);
end;
finally
JsonToSend.Free;
end;
end;

对我来说,我希望有这样一种情况,如果在 header 参数中提供了内容类型,它将使用指定的类型而不是任何预设类型。但是,由于提供了未知的媒体类型,会引发 API 异常。 API 异常如下:

Invalid mime type "application/vnd.xxxx.custom.custom-data+json, application/x-www-form-urlencoded": Invalid token character ',' in token "vnd.xxxx.custom.custom-data+json, application/x-www-form-urlencoded"

我的理解是它识别了我在参数中提供的自定义内容类型,但仍然在该请求 header 中附加了 REST.Types 中的一种预设内容类型,导致它失败。我希望它发送请求 header 为 application/vnd.xxxx.custom.custom-data+json 的正文,不包括 application/x-www-form-urlencoded .

最佳答案

显然 TRestCLient 试图在您的场景中表现得过于聪明。然而,有一种常规的方法可以解决这个问题。关键是:

  1. 向请求正文添加单个内容,该内容不能是 ctNonectMULTIPART_FORM_DATActAPPLICATION_X_WWW_FORM_URLENCODED 中的任何一个。
  2. 使用自定义 header 值覆盖 Content-Type

示例代码:

uses
System.NetConsts;

RESTClient1.BaseURL := 'https://postman-echo.com/post';
RESTRequest1.Method := rmPOST;
RESTRequest1.Body.Add('{ "some": "data" }', ctAPPLICATION_JSON);
RESTRequest1.AddParameter(sContentType, 'application/vnd.hmlr.corres.corres-data+json',
pkHTTPHEADER, [poDoNotEncode]);
RESTRequest1.Execute;

回显服务的响应是:

{
"args":{
},
"data":{
"some":"data"
},
"files":{
},
"form":{
},
"headers":{
"x-forwarded-proto":"https",
"host":"postman-echo.com",
"content-length":"18",
"accept":"application/json, text/plain; q=0.9, text/html;q=0.8,",
"accept-charset":"UTF-8, *;q=0.8",
"content-type":"application/vnd.hmlr.corres.corres-data+json",
"user-agent":"Embarcadero RESTClient/1.0",
"x-forwarded-port":"443"
},
"json":{
"some":"data"
},
"url":"https://postman-echo.com/post"
}

当然要注意回显的 header ,尤其是Content-Type。我在 Delphi 10.2 Tokyo 中测试了示例,因此希望它也能在 XE8 中运行。

编辑

您观察到的行为是 bug (RSP-14001)那是fixed in RAD Studio 10.2 Tokyo .

有多种方法可以解决这个问题。举几个例子:

  1. 调整您的 API 以丢弃次要 MIME 类型。
  2. 将您的客户端实现改为TNetHttpClient,前提是您可以放弃TRestClient 提供的所有额外优势。
  3. 升级到 RAD Studio 10.2+。
  4. Hack it!不过,强烈建议不要使用此选项,但它可以帮助您更好地理解 TRestClient 实现细节。

破解它的最简单方法是修补方法 TCustomRESTRequest.ContentType(请注意,我们正在谈论具有单个参数的不变性)以返回参数的 ContentType如果它的 AParamsArray 参数包含类型为 pkREQUESTBODY 的单个参数。这将允许我们将正文添加到 ctNone 类型的请求中,以便修补后的方法也将返回 ctNone,这将有效地防止将另一个值附加到 Content-键入 header 。

另一种选择是修补方法 TRESTHTTP.PrepareRequest 以在推断请求的内容类型之前优先使用自定义 Content-Type header 。顺便说一句,这是在 RAD Studio 10.2 Tokyo 中修复后当前实现的工作方式。此逻辑也适用于其他 header - AcceptAccept-CharsetAccept-EncodingUser-Agent .修补方法 TRESTHTTP.PrepareRequest 实现起来稍微有点困难,因为它具有 private 可见性。

最困难的选择是修补 TWinHTTPRequest.SetHeaderValue 以丢弃次要内容类型值。这也是最危险的一个,因为它会影响应用程序中任何与 HTTP 相关的内容(依赖于 THTTPClient)。修补该类也很困难,但并非不可能,因为它完全隐藏在 System.Net.HttpClient.Win.pasimplementation 部分中。这是一个巨大的耻辱,因为它还阻止您创建自定义子类。也许有充分的理由.. 谁知道 ;)

关于rest - TREST请求 : Is it possible to use custom media types in a POST request?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56430564/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com