Delphi用WinInet用用户名和密码下载文件

Posted

技术标签:

【中文标题】Delphi用WinInet用用户名和密码下载文件【英文标题】:Delphi Download File with WinInet with UserName and Password 【发布时间】:2015-02-02 22:48:52 【问题描述】:

有很多关于如何使用 WinInet 下载文件的文章(我从那里获得代码),但它们似乎都较旧和/或已关闭。没有用户名和密码的下载工作正常,但如果我用用户名和密码保护文件夹(使用 VodaHost),我在尝试下载文件时不断收到身份验证错误:

401 未经授权......

如果我通过网络浏览器访问,会弹出用户名/密码对话框,我可以正常访问。受保护的文件夹是:

http://www.mywebsite.com/downloads

我已将服务器设置为:www.mywebsite.com 并将 URL 设置为 http://www.mywebsite.com/downloads。用户名和密码已使用网络浏览器验证。

我也尝试了很多排列,但有点沮丧。我能想到的“唯一”是因为服务器没有受到保护,而是服务器上的一个文件夹。服务器无法受到保护,因为它是/将是可公开访问的。如果您需要更多信息,请告诉我。

有人有什么想法吗?

function Download(Server, Url, User, Pass, FileName : string): boolean;
const
  BUFFERSIZE = 4096;

var
  hSession: HINTERNET;
  hService: HINTERNET;
  hHTTP: HINTERNET;
  lpBuffer: array[0..BufferSize + 1] of Byte;
  BufferLength: DWORD;
  dwBytesRead: DWORD;
  dwSizeOfRq, Reserved, dwByteToRead: DWORD;
  localFile: file;
  fsize: DWORD;

begin
  try
    try
      // Downloads file at URL bypassing cache
      Result := False;

      // Initialize the Win32 Internet functions
      hSession := InternetOpen(PChar('Empyrean'), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ;
      // See if the session handle is valid
      if hSession = nil then
        Exit;

      hHTTP := InternetConnect(hSession, PChar(Server), INTERNET_DEFAULT_HTTP_PORT, PChar(User), PChar(Pass), INTERNET_SERVICE_HTTP, 0, 0);
      if hHTTP = nil then
        Exit;

      // InternetOpenUrl opens a handle to the Internet file using a URL. The flags indicate that the file will always
      // be read from the Internet rather than the cache
      //hService := InternetOpenUrl(hSession, pChar(url), nil, 0, INTERNET_FLAG_DONT_CACHE or INTERNET_FLAG_PRAGMA_NOCACHE or INTERNET_FLAG_RELOAD, 0);
      hService := InternetOpenUrl(hSession, pChar(url), nil, 0, INTERNET_FLAG_RELOAD, 0);

      // See if the session handle is valid
      if hService = nil then
      begin
        InternetCloseHandle(hService);
        Exit;
      end;

      HttpQueryInfo(hService, HTTP_QUERY_STATUS_CODE or HTTP_QUERY_FLAG_NUMBER, @dwByteToRead, dwSizeOfRq, Reserved);
      AssignFile(localFile, FileName);
      $I-
        Rewrite(localFile, 1);
     $I+
     if IOResult <> 0 then
      begin
        ShowMessage('Cannot create local file: ' + FileName);
        InternetCloseHandle(hService);
        Exit;
      end;
      BufferLength := BUFFERSIZE;

      // These three variables will store the size of the file, the size of the HttpQueryInfo content, and the number of bytes read in
      // total. Now determine the length of a file in bytes
      dwByteToRead := 0;
      dwSizeOfRq := 4; // BufferLength
      Reserved := 0;

      // get the file's size.
      if not HttpQueryInfo(hService, HTTP_QUERY_CONTENT_LENGTH or HTTP_QUERY_FLAG_NUMBER, @dwByteToRead, dwSizeOfRq, Reserved) then
        dwByteToRead := 0;
      FSize := 0;
      BufferLength := BUFFERSIZE;

      while (BufferLength > 0) do
      begin
      // Read data from the hService handle
        if not InternetReadFile(hService, @lpBuffer, BUFFERSIZE, BufferLength) then
          Break;
        if (BufferLength > 0) and (BufferLength <= BUFFERSIZE) then
          BlockWrite(localFile, lpBuffer, BufferLength);
        fsize := fsize + BufferLength;

      // Check the size of the remaining data. If it is zero, break
        if BufferLength > 0 then
          Result := True;
      end;

      CloseFile(localFile);
      Result := True;
    except

    end;
  finally
    // Close the Internet handle that the application has opened
    InternetCloseHandle(hService);
    InternetCloseHandle(hSession);
    InternetCloseHandle(hHTTP);
  end;

end;

【问题讨论】:

尝试使用像 Wireshark 这样的工具来比较浏览器请求产生的网络流量和你的程序产生的流量。或者查看服务器日志(如果有)。一旦您看到不同之处,您就会更好地了解自己做错了什么。 您是否尝试阅读MSDN Documentation? 两者都试过了,我看不出哪里出错了,即。我看不到传递用户名和密码的位置。我可以看到 401 Unauthorized 行。这在很大程度上与我在使用 WireShark 和查看服务器日志方面缺乏经验有关。 阅读 MSDN 文档后,您应该意识到您需要知道需要哪种类型的身份验证。是哪个? 【参考方案1】:

在调用InternetOpenUrl()之前,使用InternetSetOption()InternetConnect()返回的句柄指定INTERNET_OPTION_USERNAMEINTERNET_OPTION_PASSWORD值。

阅读文档了解更多详情:

Handling Authentication

特别是:

即使需要身份验证,InternetOpenUrl 和 HttpSendRequest 函数也会成功完成。 不同之处在于,头文件和 InternetReadFile 中返回的数据会收到一个 html 页面,通知用户状态码。

所以如果InternetOpenUrl() 是“成功”,你将不得不使用HttpQueryInfo() 来获取状态码,如果是 401 然后设置一个用户名/密码(如果需要提示用户)并再次尝试请求.上述文档中有一个示例。仅当状态码为 200 时,响应才会为您提供请求的实际文件。

【讨论】:

LebeauThanks,我已经把它放进去(并且又做了一次)同样的 401 Unauthorized 错误:` InternetSetOption(hHTTP, INTERNET_OPTION_PASSWORD, pChar(Pass), Length(Pass)); InternetSetOption(hHTTP, INTERNET_OPTION_USERNAME, pChar(User), Length(User));` @RRUZ 是的,但我不是专家。我“认为”我所做的是正确的,显然不是。 @David Heffernan 我想,我可能错了,INTERNET_OPTION_PASSWORD/USERNAME 告诉系统我将使用用户名和密码传递字符串。它不在显示的代码中,但我已经尝试过,并且按照 Remy 的建议再次尝试过,但无济于事。 对我的初始文本进行快速更正,URL 实际上设置为文件名(我应该相信它),而不仅仅是文件的文件夹:http://www.mywebsite.com/downloads/filetodownload.txt 使用InternetSetOption()设置字符串值时,必须使用Length()+1包含空终止符。【参考方案2】:

感谢大家的建议。我现在可以通过在 URL 中包含用户名/密码来运行代码:

Server := 'www.myServer.com';
URL := 'http://user:pSassword@www.myserver.com/downloads/filetodownload';

【讨论】:

以上是关于Delphi用WinInet用用户名和密码下载文件的主要内容,如果未能解决你的问题,请参考以下文章

Delphi - 需要 XE2 代码到 Delphi7。使用wininet下载文件

mongodb怎么用用户名密码登录

新浪微博怎么用用户名登录

Delphi 中用于 FTP 的 WinInet 包装器

用delphi填写网页(题目不难,就两个空,只要写我特定的用户名和密码就行)

使用 wininet 设置代理设置