显然TRestCLient
试图在你的场景中表现得太聪明。然而,有一个常规的方法可以解决这个问题。关键是:
- 将单个内容添加到请求正文,该内容不能是以下任何内容
ctNone
, ctMULTIPART_FORM_DATA
or ctAPPLICATION_X_WWW_FORM_URLENCODED
.
- 覆盖
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;
echo 服务的响应是:
{
"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"
}
注意回显的标题,尤其是Content-Type
当然。我在 Delphi 10.2 Tokyo 中测试了该示例,因此希望它也能在 XE8 中运行。
Edit
您观察到的行为是错误(RSP-14001) https://quality.embarcadero.com/browse/RSP-14001那是已在 RAD Studio 10.2 东京修复 https://edn.embarcadero.com/article/44747.
有多种方法可以解决这个问题。仅举几例:
-
调整您的 API丢弃辅助 mime 类型。
-
更改您的客户端实施 to
TNetHttpClient
相反,如果您可以放弃所有额外的福利TRestClient
提供。
-
Upgrade到 RAD Studio 10.2+。
-
Hack it!然而这个选项强烈劝阻,但它可以帮助你更好地理解
TRestClient
实施细节。
最简单的破解方法是修补方法TCustomRESTRequest.ContentType
(注意我们谈论的是单个参数的不变性)返回ContentType
一个参数,如果它的AParamsArray
参数包含单一参数类型pkREQUESTBODY
。这将允许我们将正文添加到类型的请求中ctNone
这样修补后的方法就会返回ctNone
以及,这将有效地防止附加另一个值Content-Type
header.
另一种选择是 patch 方法TRESTHTTP.PrepareRequest
更喜欢定制Content-Type
推断请求的内容类型之前的标头。顺便说一句,这就是当前实现在 RAD Studio 10.2 Tokyo 中修复后的工作方式。此逻辑也适用于其他标头 -Accept
, Accept-Charset
, Accept-Encoding
, User-Agent
。修补方法TRESTHTTP.PrepareRequest
实现起来稍微困难一些,因为它有private
能见度。
最难的选择是修补TWinHTTPRequest.SetHeaderValue
丢弃次要内容类型值。这也是最危险的一种,因为它会对任何与 HTTP 相关的内容(依赖于THTTPClient
)在您的应用程序中。修补类也很困难,但并非不可能,因为它完全隐藏在implementation
的部分System.Net.HttpClient.Win.pas
。这是一个巨大的耻辱,因为它还阻止您创建自定义子类。也许有充分的理由..谁知道呢;)