RAD Studio:C++:如何将自定义 Headers 添加到 TNETHTTPCient Post 操作

RAD Studio : C++ : How do I add custom Headers to a TNETHTTPCient Post Action

我很卡,希望有人能帮忙。 我必须修改现有的 C++ 项目以使用基于 REST 的新 API 与外部系统交互。本人web开发经验很少,请见谅

事实证明,这个第三方 REST 服务器不喜欢 RAD studio 中的 REST 组件!虽然我可以很容易地在互联网上获取资源来工作,但这个系统只会抛出授权错误。我使用其他组件取得了不同程度的成功。我尝试使用 TIdHTTP TNETHTTPClient & TNETHTTPRequest 组件。我不知道哪个是最好的,因为我的问题的一部分是对组件不熟悉……而且我很难找到涵盖我认为我需要做的事情的例子。自 2002 年以来 C++ Builder 书籍为零,这真的没有帮助吗?!

好的,这就是我必须“复制”的内容,但是是在 C++ 应用程序中

$.ajax({
type: "POST",
url:
"http://localhost/WebService/api/Actions/ExecuteAction?actionTypeFullName=SomeProduct.SecondGen.Common.Actions.DoSomething={GUID returned from login call},
headers: {
          'Expose-Headers': 'session-id',
          'session-id': sessionID // sessionID returned from login call
         },
data: {
   PropertyNames: [“TargetType”,”TargetID”]
   Propertyvalues: [“SecondGen.Common.Objects.Thing”,”5000”]
   SourceName: clientName
  },
dataType: JSON,
crossDomain: true,
cache: false,
success: function (msg) {
                     var result = msg;
                     displayResponse(result, responseType, "success");
                    },
error: function (errorMsg) {
                        displayResponse(errorMsg, responseType, "error");
                       }
});

这是我所了解的(见下面的代码)。当 运行 我得到一个 401 状态...所以访问被拒绝。 我认为(?) header 是不对的,但我不能确定,因为我一直在努力寻找任何这样做的例子......而且我不知道如何检查我'我正在发送。

我已经设法使用 NETHTTPClient->Post(URL,TStringList) 正确完成了登录功能。它返回了一个我存储在 this->Edit_Session_GUID->Text 中的 GUID...所以提供了 session guid

注:

“登录”后的所有调用 do 需要在 header 中提供 GUID (如下面的AJAX调用所示)。

这是我的一些代码。我觉得有很多错误,因为我觉得很无能

void __fastcall TForm2::RESTFunction ( void )
{
  UnicodeString REST_URL      = L"http://localhost/WebService/api/";
                REST_URL     += L"Actions/ExecuteAction?actionTypeFullName=";
                REST_URL     += L"SomeProduct.SecondGen.Common.Actions.DoSomething=";
                REST_URL     += L"={"+this->Edit_Session_GUID->Text+"}";

  this->EditURL->Text         = REST_URL;        //Display the URL, confirm it's OK
  // Set up HTTP Client Object
  this->HTTP_Client->Asynchronous                = false;
  this->HTTP_Client->HandleRedirects             = true;
  this->HTTP_Client->UserAgent                   = L"My Client/1.0";
  this->HTTP_Client->ContentType                 = L"application/json";
  this->HTTP_Client->AcceptEncoding              = L"UTF-8";
  // Set up Headers - this is what I think might be wrong ??
  this->HTTP_Client->CustHeaders->Clear();
  this->HTTP_Client->CustHeaders->Add(L"Expose-Headers","session-id");
  this->HTTP_Client->CustHeaders->Add(L"session-id",this->Edit_Session_GUID->Text);
  // Set up Function Variables/DATA and Run a Post Action
  // I've been trying different combinations of quotes { ' or \" or nothing }
  // as I don't know what's right
  UnicodeString PropertyNames = L"PropertyNames:['TargetTypez','TargetID']";
  UnicodeString Propertyvalues= L"Propertyvalues:['SomeProduct.SecondGen.Common.Objects.iThing', 5000]";
  UnicodeString sourceName    = L"SourceName:MyConnection";
  UnicodeString Tmp_params    = PropertyNames
                              + Propertyvalues
                              + sourceName;
  TStringStream *REST_parameters   = new TStringStream( Tmp_params );
  try
  {
     this->MemoWEBResponse->Lines->Text = this->HTTP_Client->Post(REST_URL, REST_parameters)->ContentAsString();
  }
  __finally
  {
     // can't deleted REST_parameters if web request is set to Asynchronous
     delete REST_parameters;
  }
}

注意:我根据 Remy Lebeau 看到的 post 从 TStringList(在登录函数中)切换到 TStringStream(在这个函数中)。我想它们大致相当,但他建议这样更好?

我想达到的目标

我们将不胜感激您提供的任何见解! 谢谢你们。注意安全。

好吧,我不能说我完全理解它的来龙去脉,但我确实遵循了它的观察结果。

如果没有 wireshark,我不可能做出这些观察。这似乎是您需要学习使用的工具!

所以答案是:AJAX 方面似乎在 将数据发送到服务器之前 进行翻译和转换。这是原始的“数据块”

data: {
   PropertyNames: [“TargetType”,”TargetID”]
   Propertyvalues: [“SecondGen.Common.Objects.Thing”,”5000”]
   SourceName: clientName
  },

当 AJAX 调用被 Wireshark 拦截时,它看起来像这样

Form item: "PropertyNames[]" = "TargetType"
Form item: "PropertyNames[]" = "TargetID"
Form item: "Propertyvalues[]" = "SecondGen.Common.Objects.Thing"
Form item: "Propertyvalues[]" = "5000"
Form item: "SourceName" = "TestPage"

Indy 组件或新内置的 Embarcdero TNETHTTP 组件中不存在相同的功能。您必须将数据 pre-translated 发送到 :

"PropertyNames[]= TargetType"
"& PropertyNames[]=TargetID"
"& Propertyvalues[]=SecondGen.Common.Objects.Thing"
"& Propertyvalues[]=5000"
"& SourceName=TestPage"

请注意,如果不包含“&”字符,wireshark 不会显示“Form item :”文本,因此该数据包实际上被视为“格式错误”

最后我使用了 Devart Securebridge 组件 (ScHttpWebRequest),因为我很快需要一个 SignalR Hub 组件,这是他们组件库的一部分。 Indy TIdHTTP 和 Embarcadero TNETHTTP 很可能是一样的。我只需要时间尝试修改数据:我的 amusement/education.

的有效负载

旁白:我在 devart 组件中使用的数据包格式(变量类型)是一个带有 ->WriteString & ->Poition=0 函数的 TStringStream。