【问题标题】:Bing Search API Azure Marketplace Authentication (Delphi + Indy)必应搜索 API Azure 市场身份验证(Delphi + Indy)
【发布时间】:2012-07-31 10:55:21
【问题描述】:

谁能指出正确的方向?我正在尝试使用新的 Bing API 执行网络搜索,但使用下面的代码,我不断收到“HTTP/1.1 400 Bad Request”。相同的请求在浏览器下运行良好(将用户名留空并在提示框中提供密码下的密钥)。

var
  IdHTTP1 : TIdHTTP;
  uri : string;
  myIOhandler : TIdSSLIOHandlerSocketOpenSSL;
begin
  myIOhandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  with myIOhandler do
  begin
      SSLOptions.Method := sslvTLSv1;
      SSLOptions.Mode := sslmUnassigned;
      SSLOptions.VerifyMode := [];
      SSLOptions.VerifyDepth := 0;
      host := '';
  end;

  IdHTTP1:= TIdHTTP.Create(nil);
  IdHTTP1.Request.UserAgent:= 'Mozilla/3.0 (compatible; IndyLibrary)';
  IdHTTP1.Request.Accept := 'text/javascript';
  IdHTTP1.Request.ContentType := 'application/json';
  IdHTTP1.Request.ContentEncoding := 'utf-8';

  IdHTTP1.HandleRedirects:= True;
  IdHTTP1.ConnectTimeout:= 10000;
  IdHTTP1.ReadTimeout:= 10000;
  IdHTTP1.Request.CacheControl := 'no-cache';
  IdHTTP1.Request.BasicAuthentication:= True;
  IdHTTP1.Request.Authentication:= TIdBasicAuthentication.Create;
  IdHTTP1.Request.Authentication.Username:= '';
  IdHTTP1.Request.Authentication.Password:= APIKey;//Encode64(APIKey);//Encode64(APIKey+':'+APIKey)
  IdHTTP1.IOHandler:= myIOHandler;

  uri:= 'https://api.datamarket.azure.com/Bing/SearchWeb/Web?'+
          'Query=%27'+ query_text +'%27&$format=JSON&$top=50&$skip=0';
  s:= IdHTTP1.Get(uri);  

MS 文档很差。

【问题讨论】:

  • 您确定 HTTP 基本身份验证应该使用空用户名吗? query_text 是否正确“URL 编码”?
  • 根据迁移指南文档:“将用户名字段留空,并在密码字段中输入您的帐户密钥。”
  • 只是为了测试,我没有使用任何需要编码的字符。我稍后会处理。相同的字符串在浏览器中有效。
  • 要找到 Indy 和浏览器请求的差异,您可以使用 Fiddler 等 HTTP 代理
  • 我认为问题出在身份验证中,正如您在我的代码中看到的那样,我尝试使用 Base64 编码。有一些与 java 相关的帖子,他们使用 base64.encode,如 base64Encode(key:key)。再次没有太多可用信息...)旧的 Bing API 明天将停止工作)

标签: delphi azure delphi-xe bing indy10


【解决方案1】:

TIdHTTP 自动为您处理 Basic 身份验证。只需设置IdHTTP1.Request.BasicAuthentication := True,然后填写IdHTTP1.Request.UsernameIdHTTP1.Request.Password 属性。你不需要直接和TIdBasicAuthentication打交道。

如果您想支持其他身份验证,例如 NTLM,只需将相关的 IdAuthentication... 单元或 IdAllAuthentication 单元添加到您的 uses 子句。

如果您想支持 Indy 本身不支持的自定义身份验证,您还可以实现自己的自定义 TIdAuthentication 派生类。您可以调用RegisterAuthenticationMethod() 以便TIdHTTP 可以自动使用您的自定义类,或者您可以使用TIdHTTP.OnSelectAuthorization 事件根据每个请求手动分配类。

【讨论】:

    【解决方案2】:

    我认为问题出在用户名上。使用基本身份验证,您需要发送如下所示的标头:

    Authorization: Basic BASE64ENC(username:password)
    

    由于在您的情况下用户名是空的,您实际上是在发送这个:

    Authorization: Basic BASE64ENC(:password)
    

    尽管文档说将用户名留空,但这仅适用于您通过浏览器访问页面时。查看文档末尾的代码示例,您会发现在许多示例中,用户名和密码都是帐户密钥:

    bingContainer.Credentials = new NetworkCredential(accountKey, accountKey);
    

    我建议你在你的代码中做同样的事情:

    IdHTTP1.Request.Authentication:= TIdBasicAuthentication.Create;
    IdHTTP1.Request.Authentication.Username:= APIKey;
    IdHTTP1.Request.Authentication.Password:= APIKey;
    

    【讨论】:

    • 感谢您的建议,但它不起作用。我将替换我的 OpenSSL 库并使用 SSL 选项进行调整,也许它们与它有关。
    • TIdHTTP 自动为您处理基本身份验证。只需设置IdHTTP1.Request.BasicAuthentication := True,然后填写IdHTTP1.Request.UsernameIdHTTP1.Request.Password 属性。无需直接与TIdBasicAuthentication打交道。
    猜你喜欢
    • 2012-06-23
    • 1970-01-01
    • 2016-07-22
    • 2016-12-21
    • 2017-02-04
    • 2013-06-28
    • 1970-01-01
    • 2016-07-26
    • 2015-11-11
    相关资源
    最近更新 更多