访问一个 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 的方式。