采用 TIdHTTP 访问 https 的网站,采用 TIdTCPClient 访问 https 的网站

访问一个 WEB 网站,如果采用 HTTP 的话,直接使用 TIdHTTP 这个控件,最简单的用法是:

S := IdHTTP1.Get('www.qq.com');

这里返回的 S 就是对应的网页的文本内容。

如果要访问 https 的网站,则需要 SSL 库。在 Windows 底下,去 https://indy.fulgan.com/SSL/ 下载最新的 SSL 的库。下载后,解压缩,包括两个 dll 文件:ssleay32.dll 和 libeay32.dll;直接放到你的程序编译好的 EXE 相同文件夹底下就可以了。运行期你的程序会自动加载这两个 DLL 完成 SSL 的功能。

设计期,拖一个 TIdSSLIOHandlerSocketOpenSSL 过来,然后设置 IdHTTP1 的属性:

1. IOHandler 这个属性,下拉,选择 IdSSLIOHandlerSocketOpenSSL1;

2. HandleRedirects 属性:设置为 True;默认是 False;

另外,要注意设置一下 IdSSLIOHandlerSocketOpenSSL1 的属性:SSLOptions -> Method 这个属性,设置为:sslvTLSv1_1

然后采用这行代码就搞定:S := IdHTTP1.Get('https://www.qq.com');

---------   分隔符 ---------------

那么,如果直接采用 TCP 连接,自己写 HTTP 请求内容,该怎么做?

毕竟,HTTP 底下是 TCP。一个 HTTP 请求,客户端向服务器发起的是一次 TCP 连接。

如果是普通的 HTTP 的话,拖一个 TIdTCPClient 过来,将这个 IdTCPClient1 连上服务器,发送正确的 HTTP 请求内容给服务器,然后读服务器发送回来的数据,一次 HTTP 访问就完成了。

大概代码如下:

SL := TStringList.Create;
  SL.LoadFromFile(ExtractFilePath(Application.ExeName) + 'test3.txt');
  S := SL.Text;

  B := BytesOf(S);

  IdTCPClient1.Host := 'www.qq.com';
  IdTCPClient1.Port := 80;
  IdTCPClient1.Connect;
  IdTCPClient1.IOHandler.Write(TIdBytes(B));;

  SR := '';

  while True do
  begin
    try
      St := IdTCPClient1.IOHandler.ReadString(200);
      SR := SR + ST;
    except
      Break;
    end;
  end;

  SR := SR + ST;
  Memo1.Lines.Add(SR);
  ShowMessage('访问结束!');
  IdTCPClient1.Disconnect;

上述代码中,要设置 TCP 客户端控件需要去连接的服务器的地址,这里我写的是 www.qq.com;要设置 TCP 要去连接的服务器的端口号。对于 HTTP 的网站,默认是 80;

留意上述代码里面的 test3.txt,这个是 HTTP 请求的内容。本质上,通过TCP发给服务器正确的 HTTP 请求内容,就能获得服务器正确的页面内容返回。

HTTP 请求的内容,是纯文本。假设我们需要访问一个页面:http://www.qq.com/123.html?id=123&UID=abc,那么,这个 HTTP 请求的文本大致是:

GET /www.qq.com/123.html?id=123&UID=abc 

发送完这个文本后,还要继续发送几个 HTTP 的头。HTTP 的头基本上就说 name:value 的格式,中间是冒号分隔。HTTP 头都有哪些详细定义,请自行上网搜索。

发送完 HTTP 的头以后,多发一个空行(也就是发送两个字符:回车,换行)。

上述的 HTTP 请求内容和 HTTP 头,为了避免代码的麻烦,我就把它写入了 test3.txt 里面。

然后可以开始在 TCP 客户端控件上读来自服务器端的内容,也就是网页内容。

经过这样的实验代码,我们可以更深入地了解 HTTP 请求是怎么一回事。

----------------------    分隔符  -------------------------------

那么,对于 https 呢?是否仍然可以用 TCP 连接去搞定?当然可以。

仍然采用 TIdTCPClient 去建立一条到网站服务器的 TCP 连接。但是,因为要用到 SSL,所以这里我们要指定 IdTCPClient1 的 IoHandler 的属性,是上面我们拖过来的 IdSSLIOHandlerSocketOpenSSL1 这个控件。当然也要记得运行期的 EXE 文件的目录底下要放那两个 SSL 的库的 DLL 文件。

接下来仍然是从 TCP 连接上发送 HTTP 请求文本包括 HTTP 头去服务器,然后读服务器发送回来的网页内容。

这里唯一要注意的是,如果是 HTTP,发送的 HTTP 请求文本是:

'GET /www.qq.com/123.html HTTP/1.1'

这么一行字符串。

但是,如果是 https 的请求,这行字符串里面,一定要加上  https:// 也就是说,要把完整的 URL 发送过去。否则服务器会返回 URI 错误的提示文字。也就是说,需要改为:

'GET https://www.qq.com/123.html HTTP/1.1'

以下是测试成功的代码:

procedure TForm1.Button9Click(Sender: TObject);
var
  S: string;
  SL: TStringList;
  Ib: TIdBytes;
  B: TBytes;
begin
  SL := TStringList.Create;
  try
    SL.Add('GET https://new.qq.com/omn/20190419/CRI2019041900641200  HTTP/1.1 ');
    SL.Add('Host: www.qq.com');
    SL.Add('Accept:*/* ');
    SL.Add('');

    S := SL.Text;
  finally
    SL.Free;
  end;

  B := BytesOf(S);
  SetLength(IB, Length(B));
  Move(B[0], IB[0], Length(B));

  IdTCPClient2.Host := 'www.qq.com';
  IdTCPClient2.Port := 443;
  IdTCPClient2.Connect;
  IdTCPClient2.IOHandler.Write(Ib);

  SetLength(IB, 0);
  IdTCPClient2.IOHandler.ReadBytes(Ib, -1, False);

  SetLength(B, Length(Ib));
  Move(Ib[0], B[0], Length(B));

  S := StringOf(B);
  Memo2.Lines.Add(S);
end;

上述代码,确实返回了真实页面的内容。

那么,https 访问时,里面的来回几个加密过程在哪里?在 Delphi 的 Indy 的架构下,估计是 IdSSLIOHandlerSocketOpenSSL1 调用 Open SSL 的 DLL 库的代码,帮我们搞定了。我们只需要专注 HTTP 请求本身就可以了。

综上所述,一个 https 的请求,本质上就是客户端到服务器端的 443 端口的一条 TCP 连接,在这条连接上,客户端发送 HTTP 请求的文本和 HTTP 的头,服务器端会返回正确的 HTTP 的应答。当然,这条 TCP 连接上跑的是加密数据,加密是 SSL 的方式。

发布了116 篇原创文章 · 获赞 19 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/pcplayer/article/details/89434464