Delphi - URL 的文件大小 - 错误 12150
Posted
技术标签:
【中文标题】Delphi - URL 的文件大小 - 错误 12150【英文标题】:Delphi - File size by URL - error 12150 【发布时间】:2013-01-30 12:25:13 【问题描述】:Delphi 6 教授,Win7 操作系统。
我有这段代码可以通过 URL 获取文件大小:
function TDDWIToolObject.GetFileSize(out Size: Int64): boolean;
var
hInet: HINTERNET;
hRequest : HINTERNET;
lpdwBufferLength: DWORD;
lpdwReserved : DWORD;
ServerName: string;
Resource: string;
FileSizeBuffer : array[0..32] of char;
//SizeCard : Cardinal;
begin
ParseURL(Url, ServerName, Resource);
Result := False;
Size := 0;
hInet := InternetOpen(PChar(_UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if hInet=nil then begin
FErrorCode := GetLastError;
Exit;
end;
try
hRequest := InternetOpenUrl(hInet, PChar(URL), PCHar(Headers), Length(HEaders), 0, 0);
try
FillChar(FileSizeBuffer, SizeOf(FileSizeBuffer), #0);
lpdwBufferLength := SizeOf(FileSizeBuffer);
lpdwReserved :=0;
if not HttpQueryInfo(
hRequest,
HTTP_QUERY_CONTENT_LENGTH,
@FileSizeBuffer, lpdwBufferLength, lpdwReserved) then begin
FErrorCode:=GetLastError;
Exit;
end;
Size := StrToInt64(StrPas(FileSizeBuffer));
Result := True;
finally
InternetCloseHandle(hRequest);
end;
finally
InternetCloseHandle(hInet);
end;
end;
在我的机器 + DSL 连接上运行良好。
但是当我在其他完全受保护的地方(代理+许多策略)检查此代码时,我得到错误代码 12150... :-(
有趣的是,当我使用这段代码时,我可以下载这个文件:
function TDDWIToolObject.DownloadFile;
var
hInet: HINTERNET;
hFile: HINTERNET;
pbuffer: Pointer;
bytesRead: DWORD;
Stm : TFileStream;
TotalBytes : Int64;
AbortIt : boolean;
begin
Result := False;
FErrorCode := -1;
FAborted := False;
hInet := InternetOpen(PChar(_UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if hInet = nil
then begin
FErrorCode := GetLastError;
Exit;
end;
try
hFile := InternetOpenURL(hInet, PChar(URL), PChar(FHeaders), Length(FHeaders), 0, 0);
if hFile = nil
then begin
FErrorCode := GetLastError;
Exit;
end;
try
Stm := TFileStream.Create(FN, fmCreate);
try
GetMem(pbuffer, FBufferSize);
try
TotalBytes := 0; AbortIt := False;
while (not FAborted) do begin
if not InternetReadFile(hFile, pbuffer, FBufferSize, bytesRead) then begin
FErrorCode := GetLastError;
Exit;
end;
if bytesRead > 0 then begin
Stm.WriteBuffer(pbuffer^, bytesRead);
if Assigned(FOnBytesArrived)
then begin
inc(TotalBytes, bytesRead);
FOnBytesArrived(Self, TotalBytes, AbortIt);
if AbortIt
then Abort;
end;
end else begin
break;
end;
end;
finally
FreeMem(pbuffer);
end;
if not FAborted
then Result := True;
finally
Stm.Free;
end;
finally
InternetCloseHandle(hFile);
end;
finally
InternetCloseHandle(hInet);
end;
end;
这很有趣,因为系统管理员允许在代理中对这个 URL 的请求,并且下载对我有用 - 只有内容长度请求失败。
我想问一个问题,但很难做到,因为其中很多都在我的脑海中...... 您知道我们可以做些什么来允许这些请求吗? 也许 HttpRequest 使用另一个端口,或者一些“非法”的不可代理? 或者我的代码似乎是错误的?为什么它在非保护区工作?下载和获取内容长度请求有什么区别?
所以问题是总结格式:你知道我可以做些什么来在下载之前获取文件大小吗?
谢谢。
【问题讨论】:
不,如果我添加 flag_number,我得到的结果是数字(我知道红衣主教)。我更喜欢符合 Int64 的字符串。 【参考方案1】:这个错误可能是由很多因素引起的(ERROR_HTTP_HEADER_NOT_FOUND),在你的代码中你没有在调用HttpQueryInfo
方法之前检查InternetOpenUrl
函数的结果,我没有看到的内容_UserAgent
和 Headers
变量给你一个更准确的答案。无论如何尝试使用HttpOpenRequest
和HttpSendRequest
函数而不是InternetOpenURL
。
试试这个示例
uses
Windows,
SysUtils,
WinInet;
const
sUserAgent = 'Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101';
function GetWinInetError(ErrorCode:Cardinal): string;
const
winetdll = 'wininet.dll';
var
Len: Integer;
Buffer: PChar;
begin
Len := FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE or FORMAT_MESSAGE_FROM_SYSTEM or
FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_IGNORE_INSERTS or FORMAT_MESSAGE_ARGUMENT_ARRAY,
Pointer(GetModuleHandle(winetdll)), ErrorCode, 0, @Buffer, SizeOf(Buffer), nil);
try
while (Len > 0) and $IFDEF UNICODE(CharInSet(Buffer[Len - 1], [#0..#32, '.'])) $ELSE(Buffer[Len - 1] in [#0..#32, '.']) $ENDIF do Dec(Len);
SetString(Result, Buffer, Len);
finally
LocalFree(HLOCAL(Buffer));
end;
end;
procedure ParseURL(const lpszUrl: string; var Host, Resource: string);
var
lpszScheme : array[0..INTERNET_MAX_SCHEME_LENGTH - 1] of Char;
lpszHostName : array[0..INTERNET_MAX_HOST_NAME_LENGTH - 1] of Char;
lpszUserName : array[0..INTERNET_MAX_USER_NAME_LENGTH - 1] of Char;
lpszPassword : array[0..INTERNET_MAX_PASSWORD_LENGTH - 1] of Char;
lpszUrlPath : array[0..INTERNET_MAX_PATH_LENGTH - 1] of Char;
lpszExtraInfo : array[0..1024 - 1] of Char;
lpUrlComponents : TURLComponents;
begin
ZeroMemory(@lpszScheme, SizeOf(lpszScheme));
ZeroMemory(@lpszHostName, SizeOf(lpszHostName));
ZeroMemory(@lpszUserName, SizeOf(lpszUserName));
ZeroMemory(@lpszPassword, SizeOf(lpszPassword));
ZeroMemory(@lpszUrlPath, SizeOf(lpszUrlPath));
ZeroMemory(@lpszExtraInfo, SizeOf(lpszExtraInfo));
ZeroMemory(@lpUrlComponents, SizeOf(TURLComponents));
lpUrlComponents.dwStructSize := SizeOf(TURLComponents);
lpUrlComponents.lpszScheme := lpszScheme;
lpUrlComponents.dwSchemeLength := SizeOf(lpszScheme);
lpUrlComponents.lpszHostName := lpszHostName;
lpUrlComponents.dwHostNameLength := SizeOf(lpszHostName);
lpUrlComponents.lpszUserName := lpszUserName;
lpUrlComponents.dwUserNameLength := SizeOf(lpszUserName);
lpUrlComponents.lpszPassword := lpszPassword;
lpUrlComponents.dwPasswordLength := SizeOf(lpszPassword);
lpUrlComponents.lpszUrlPath := lpszUrlPath;
lpUrlComponents.dwUrlPathLength := SizeOf(lpszUrlPath);
lpUrlComponents.lpszExtraInfo := lpszExtraInfo;
lpUrlComponents.dwExtraInfoLength := SizeOf(lpszExtraInfo);
InternetCrackUrl(PChar(lpszUrl), Length(lpszUrl), ICU_DECODE or ICU_ESCAPE, lpUrlComponents);
Host := lpszHostName;
Resource := lpszUrlPath;
end;
function GetRemoteFileSize(const Url : string): Integer;
var
hInet : HINTERNET;
hConnect : HINTERNET;
hRequest : HINTERNET;
lpdwBufferLength: DWORD;
lpdwReserved : DWORD;
ServerName: string;
Resource: string;
ErrorCode : Cardinal;
begin
ParseURL(Url,ServerName,Resource);
Result:=0;
hInet := InternetOpen(PChar(sUserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if hInet=nil then
begin
ErrorCode:=GetLastError;
raise Exception.Create(Format('InternetOpen Error %d Description %s',[ErrorCode,GetWinInetError(ErrorCode)]));
end;
try
hConnect := InternetConnect(hInet, PChar(ServerName), INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
if hConnect=nil then
begin
ErrorCode:=GetLastError;
raise Exception.Create(Format('InternetConnect Error %d Description %s',[ErrorCode,GetWinInetError(ErrorCode)]));
end;
try
hRequest := HttpOpenRequest(hConnect, PChar('HEAD'), PChar(Resource), nil, nil, nil, 0, 0);
if hRequest<>nil then
begin
try
lpdwBufferLength:=SizeOf(Result);
lpdwReserved :=0;
if not HttpSendRequest(hRequest, nil, 0, nil, 0) then
begin
ErrorCode:=GetLastError;
raise Exception.Create(Format('HttpOpenRequest Error %d Description %s',[ErrorCode,GetWinInetError(ErrorCode)]));
end;
if not HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH or HTTP_QUERY_FLAG_NUMBER, @Result, lpdwBufferLength, lpdwReserved) then
begin
Result:=0;
ErrorCode:=GetLastError;
raise Exception.Create(Format('HttpQueryInfo Error %d Description %s',[ErrorCode,GetWinInetError(ErrorCode)]));
end;
finally
InternetCloseHandle(hRequest);
end;
end
else
begin
ErrorCode:=GetLastError;
raise Exception.Create(Format('HttpOpenRequest Error %d Description %s',[ErrorCode,GetWinInetError(ErrorCode)]));
end;
finally
InternetCloseHandle(hConnect);
end;
finally
InternetCloseHandle(hInet);
end;
end;
【讨论】:
另外,请记住,并非所有 HTTP 响应,尤其是 HTTP 1.1 响应,都有Content-Length
标头,但仍然可以传输数据。这是通过通过Transfer-Encoding: chunked
标头对响应进行分块来实现的,在这种情况下,计算文件大小的唯一方法是实际完整下载它。以上是关于Delphi - URL 的文件大小 - 错误 12150的主要内容,如果未能解决你的问题,请参考以下文章