问题
There are numerous articles of how to download a file using WinInet (that's where I got the code from), but they all seem to be older and/or closed. Downloading without a username and password works fine, but if I protect the folder (Using VodaHost) with username and password I keep getting an authentication error when trying to download a file:
401 Unauthorized......
If I access through a web browser the username/password dialog pops up and I can get in fine. The folder protected is:
http://www.mywebsite.com/downloads
I have set Server to: www.mywebsite.com and url to http://www.mywebsite.com/downloads. The username and paswsord has been validated using a web browser.
I have also tried many permutations and am getting a bit frustrated. The 'only' thing I can think of is that it's because the server is not protected, but a folder on the server. The server cannot be protected because it is/will be publicly accessible. If you need any more info just let me know.
Anyone have any ideas?
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;
回答1:
Use InternetSetOption() to specify INTERNET_OPTION_USERNAME
and INTERNET_OPTION_PASSWORD
values for the handle returned by InternetConnect()
, before calling InternetOpenUrl()
.
Read the documentation for more details:
Handling Authentication
In particular:
The InternetOpenUrl and HttpSendRequest functions complete successfully even when authentication is required. The difference is, the data returned in the header files and InternetReadFile would receive an HTML page informing the user of the status code.
So if InternetOpenUrl()
is "successful", you will have to use HttpQueryInfo()
to get the status code, and if it is 401 then set a username/password (prompting the user if needed) and try the request again. There is an example of that in the above documentation. The response provides you with the actual file requested only if the status code is 200.
回答2:
Thanks to all for the advice. I now have the code working by including the username/password in the URL:
Server := 'www.myServer.com';
URL := 'http://user:pSassword@www.myserver.com/downloads/filetodownload';
来源:https://stackoverflow.com/questions/28288305/delphi-download-file-with-wininet-with-username-and-password