TRESTRequest:是否可以在 POST 请求中使用自定义媒体类型?

2024-05-05

例如,我们有一个 API,需要我们自己的供应商特定内容类型application/vnd.xxxx.custom.custom-data+json但查看 REST.Client 的源代码,它似乎总是默认为 REST.Types 中的 ContentType 之一,例如在分配时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;

对我来说,我希望存在一种情况,如果在标头参数中提供了内容类型,它将使用指定的内容类型而不是任何预设的内容类型。但是,由于提供了未知的媒体类型,因此会引发 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"

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


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

  1. 将单个内容添加到请求正文,该内容不能是以下任何内容ctNone, ctMULTIPART_FORM_DATA or ctAPPLICATION_X_WWW_FORM_URLENCODED.
  2. 覆盖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.

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

  1. 调整您的 API丢弃辅助 mime 类型。
  2. 更改您的客户端实施 to TNetHttpClient相反,如果您可以放弃所有额外的福利TRestClient提供。
  3. Upgrade到 RAD Studio 10.2+。
  4. 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。这是一个巨大的耻辱,因为它还阻止您创建自定义子类。也许有充分的理由..谁知道呢;)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TRESTRequest:是否可以在 POST 请求中使用自定义媒体类型? 的相关文章

  • 如何触发应用程序通过 REST 服务获取数据?

    我正在寻找一种方法来触发应用程序从远程 REST 服务获取数据 该方法不需要轮询 iOS 推送通知似乎不是一个选项 因为它可以被用户停用 然而 我可能是错的 是否有最佳实践来完成此任务 实际上 推送通知是可行的方法 在 ios8 及更高版本
  • 如何在没有 baseUrl 的情况下设置 Retrofit

    我的 apiPath 是完全动态的 我有包含 ipAddress 和 SSLprotocol 等字段的项目 基于它们我可以构建我的网址 private String urlBuilder Server server String proto
  • 如何在Delphi中下载一个非常简单的HTTPS页面?

    我尝试了在这里看到的代码 但它不适用于 HTTPS 我需要将此页面作为字符串下载 并在其上添加一些换行符 以便将信息按顺序放入 TMemo 中 怎么做 我尝试使用 Indy 但由于 SSL 问题而失败 我尝试了此页面的解决方案 如何将网页下
  • 为什么“FormDataMultiPart”类型参数被区别对待

    我正在编写一个小网络应用程序 将文件上传到网络服务器 我一切正常 但令我感到困惑的是 几乎所有从客户端 浏览器 发送的参数都必须在服务器端注入单词 FormDataParam except FormDataMultiPart类型参数 有人可
  • 是否可以修改 $_SESSION 变量?

    恶意用户是否可以将 SESSION 在 php 中 变量设置为他想要的任何值 很大程度上取决于您的代码 有一点非常明显 SESSION username REQUEST username
  • 处理 TShellListView 后代中的文件放置

    我正在尝试创建 TShellListView 的后代 它接受从 Windows 资源管理器中删除的文件 我想在组件定义中处理拖 放操作 而不必在任何使用该组件的应用程序中实现它 我找到了接受从 Windows 资源管理器中拖放的文件的示例
  • 由于浏览器设置的标头,Safari 拒绝重定向的 CORS 请求

    Summary Safari 拒绝一些涉及重定向的 CORS 请求 声称某些标头是不允许的 但该标头从来不是由脚本请求的 而是由浏览器添加的 所以我认为这应该不重要 Safari 的行为是一个错误吗 规格有问题吗 或者 事情变成这样是有原因
  • Jersey 和 Spring 中的全局异常处理?

    我正在使用 Jersey 和 Spring 3 2 以及 Open CMIS 开发 RESTful Web 服务 我没有使用 Spring 的 MVC 模式 它只是 Spring IOC 和 Jersey SpringServlet 控制器
  • 以 RESTful 方式增加资源计数器:PUT 与 POST

    我有一个带有计数器的资源 为了举例 我们将该资源称为profile 计数器是数量views对于该配置文件 Per the 休息维基 http rest blueoxen net cgi bin wiki pl HttpMethods PUT
  • Word 2010 自动化:“转到书签”

    我有一个用 Delphi 7 编写的程序 它打开一个基于模板的新 Word 文档 文档打开后 系统会自动跳转到书签 在模板中预定义 并在其中添加一些文本 以下代码在 Word 2003 中工作正常 但会导致invalid variant o
  • 响应 301 永久移动

    我曾经得到以下对 php 请求的响应 回复
  • HTTP代理服务器

    我开始研究一个用 C 编写的非常基本的 HTTP 代理服务器 Edit 只是转发我的请求的东西 此时我很难理解如何继续 任何帮助都会有益的 看一眼micro proxy http acme com software micro proxy
  • 返回重定向作为对 Ajax(fetch、XHR 等)请求的响应

    如果浏览器收到对 ajax 请求的重定向响应 会发生什么 如果浏览器收到对 ajax 请求的重定向响应 会发生什么 如果服务器发送重定向 又名 302 响应加上 Location 标头 浏览器将自动遵循重定向 对此的回应second请求 假
  • iPhone 应用程序中的异步、同步、线程

    我正处于一个应用程序的设计阶段 该应用程序将利用 REST Web 服务 并且在使用异步 同步和线程方面遇到了困境 这是场景 假设您有三个选项可供深入研究 每个选项都有自己的基于 REST 的资源 我可以使用同步请求延迟加载每个请求 但这会
  • 当responseText包含有效的Xml时,IXMLHttpRequest.responseXml为空,没有解析错误

    我正在从中获取一些 XML政府网站 http www bankofcanada ca stats assets rates rss noon en all xml http www bankofcanada ca stats assets
  • 有没有办法使用 ASP.NET 在用户离开页面时始终运行某些服务器端代码?

    我想知道当用户离开 ASP NET 中的页面时是否有任何方法可以始终运行一些服务器端代码 页面卸载事件不好 因为如果有人单击链接 则不会调用该事件 理想情况下 即使用户关闭浏览器 我也希望代码能够运行 我怀疑我所问的问题是不可能的 但问一下
  • Access-Control-Allow-Origin值跨站缓存

    我正在尝试编写一个 nginx 配置来处理 http 和 https 上的两个站点 只要客户端从不访问这两个站点 它似乎就可以工作 但如果它们这样做 就会出现缓存 跨站点问题 Allow cross origin location eot
  • 如何使用 Ruby on Rails 3 检查 HTTP 请求的“Content-Length”字段?

    我正在使用 Ruby on Rails 3 在我的视图文件中我有以下代码 为了避免服务器过载 我会在服务器接收上传文件之前检查上传文件的大小 这是因为 按下表单的提交按钮 服务器会先完整接收文件 然后再检查文件 我知道一个HTTP 请求有标
  • Spring @RequestMapping 带有可选参数

    我的控制器在请求映射中存在可选参数的问题 请查看下面的控制器 GetMapping produces MediaType APPLICATION JSON VALUE public ResponseEntity
  • 浏览器显示 clojure 环中不存在 access-control-allow-origin 标头

    我通过客户端浏览器向服务器发出请求 如下所示https example com bar https example com bar 但出现错误 Access to XMLHttpRequest at https example com ba

随机推荐