POST 使用 Indy 或 TWebBrowser 发送到 Tableau Server 的注销消息失败

POST signout message to Tableau Server fails using Indy or TWebBrowser

在使用 Tableau Server API 测试版 2018.2 时,文档列出了一个 REST api 调用,该调用在自定义应用程序和Tableau 服务器。

session 通过使用用户名和密码执行 POST 请求(登录)来保护,该用户名和密码获取用于进一步请求的令牌。

当 session 完成后,要遵循的正确安全协议是签署 out/close session。通过创建包含令牌的自定义身份验证 header 字符串,这与请求流程的方式非常相似。

执行注销时有一个显着差异,即对 'signout' 的请求是 POST 请求,而不是 GET 请求。虽然这应该不会造成问题,但它似乎是一个问题。

注销 POST 请求与任何其他 POST 请求的主要区别在于注销请求的数据是 nil/null。基于 API 文档没有提及这一点,而是给出了一个简单的 CURL 示例:

curl "http://MY-SERVER/api/3.0/auth/signout" -X POST -H "X-Tableau-Auth:12ab34cd56ef78ab90cd12ef34ab56cd"

...必须假设在不发送数据的情况下执行 POST 请求的行为被视为正常功能。

我已经使用 TIdHTTP 组件尝试了此请求,并为 post 调用中的 POST 数据参数提供了一个空的 TStringStream 或一个空的 TStringList:

try
  tss := TStringStream.Create('');
  http.Request.RawHeaders.AddValue('X-Tableau-Auth',FToken);
  http.Post('http://<myserver>/api/3.0/auth/signout',tss);
finally
  tss.Free;
end;

...但收到 'HTTP/1.1 401 Unauthorized' 异常。

如果我尝试使用 TWebBrowser 界面执行此操作:

var
  flags,headers,postdata,targetframe,url: OleVariant;
begin
  url := 'http://<myserver>/api/3.0/auth/signout';
  headers := 'X-Tableau-Auth: ' + FToken + #13#10;
  targetframe := 1;
  flags := 1;
  postdata := VarArrayCreate([0,1],varByte);
  postdata[0] := 1;
  Navigate2(URL,flags,targetframe,postdata,Headers);
end;

...我第一次意外启动 Internet Exploder,在 url 框中注销 url,并且显示的页面显示 'Navigation canceled'。

如果我再次 运行 代码,我将启动另一个不需要的 Internet Exploder,这次是 response/page:

<?xml version="1.0" encoding="UTF-8"?>
-<tsResponse xsi:schemaLocation="http://tableau.com/api http://tableau.com/api/ts-api-3.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tableau.com/api">
-<error code="401002">
<summary>Unauthorized Access</summary>
<detail>Invalid authentication credentials were provided.</detail>
</error>

我更愿意使用 TIdHttp 组件来完成这个小任务,但必须使用 TWebBrowser 来完成视觉任务,所以我也可以使用它。

这是 link 用于注销 api 调用的 Tableau Server 文档:

https://onlinehelp.tableau.com/current/api/rest_api/en-us/help.htm#REST/rest_api_ref.htm#Sign_Out%3FTocPath%3DAPI%2520Reference|_____90

TIdHTTP准备发送新的HTTP请求时,TIdHTTP.Request.RawHeaders属性被清除,re-populated与实际的headers将被寄出。由于您将 session 令牌存储在 RawHeaders 中,它会被清除并且不会发送到服务器,这就是您收到 401 错误的原因。

您需要使用 TIdHTTP.Request.CustomHeaders 属性,它在准备请求时添加到 RawHeaders

tss := TStringStream.Create('');
try
  http.Request.CustomHeaders.AddValue('X-Tableau-Auth',FToken);
  // or:
  // http.Request.CustomHeaders.Values['X-Tableau-Auth'] := FToken;
  http.Post('http://<myserver>/api/3.0/auth/signout', tss);
finally
  tss.Free;
end;

仅供参考,如果你想 post 清空数据,你可以传入一个 nil 源指针:

http.Post('http://<myserver>/api/3.0/auth/signout', TStream(nil));

http.Post('http://<myserver>/api/3.0/auth/signout', TStrings(nil));

好的,明白了。在我的代码中,没有添加带有身份验证信息的 header。此外,将 http.Connection 设置为 'close'。

问题解决了。