【发布时间】:2021-10-05 23:53:31
【问题描述】:
我正在使用 StringStream 读取发送到 chromedriver 的命令的结果。
问题是返回的结果弄乱了内存地址,它给了我一个访问冲突错误。
我尝试了多种不同的方法来捕获异常,但程序停止工作。当我使用断点时,我看到 DataString 具有请求的值,但是当它尝试将其放入变量中时,它会终止程序。
这是我正在使用的代码:
function TDelphiCommand.ExecutePost(port: WORD; const URL, Data: string): string;
var
Header : TStringStream;
pSession : HINTERNET;
pConnection : HINTERNET;
pRequest : HINTERNET;
flags : DWord;
AcceptType: array[0..1] of PChar;// = ('*/*', nil);
sStream: TStringStream;
Buffer: array[0..255] of Byte;
aBufferSize: Cardinal;
b1: Boolean;
AData: TMemoryStream;
sUrl: string;
aMem: PByte;
begin
Result := '';
pSession := InternetOpen('Mozila/5.0', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if Assigned(pSession) then
try
pConnection := InternetConnect(pSession, '127.0.0.1', port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
if Assigned(pConnection) then
try
AcceptType[0] := 'application/json';
AcceptType[1] := nil;
sUrl := Copy(URL, Pos(IntToStr(port), URL)+Length(IntToStr(port))+1, Length(URL));
pRequest := HTTPOpenRequest(pConnection, 'POST', PChar(sUrl), 'HTTP/1.1', nil, @AcceptType[0], INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_ASYNC or INTERNET_FLAG_MAKE_PERSISTENT, 0);
if Assigned(pRequest) then
try
Header := TStringStream.Create('');
try
with Header do
begin
WriteString('Accept: text/html, application/json, application/xhtml+xml, image/jxr, */*' + sLineBreak);
WriteString('Accept-Encoding: gzip, deflate' + sLineBreak);
WriteString('Accept-Language: en-US, en; q=0.5' + sLineBreak);
//text/html
WriteString('Content-Type: application/json; charset=UTF-8' + sLineBreak);
WriteString('Connection: keep-alive'+ SlineBreak);
WriteString('Host: 127.0.0.1' + sLineBreak);
WriteString('User-Agent: Mozilla/5.0'+ sLineBreak);
end;
HttpAddRequestHeaders(pRequest, PChar(Header.DataString), Length(Header.DataString), HTTP_ADDREQ_FLAG_ADD);
AData := TMemoryStream.Create;
try
AData.Write(TEncoding.UTF8.GetBytes(Data), Length(Data));
b1 := HTTPSendRequest(pRequest, nil, 0, AData.Memory, AData.Size);
if b1 then
begin
sStream := TStringStream.Create('');
try
try
sStream.Position := 0;
while InternetReadFile(pRequest, @Buffer[0], SizeOf(Buffer), aBufferSize) and (aBufferSize <> 0) do
sStream.Write(Buffer[0], aBufferSize);
Result := sStream.Datastring;//UTF8ToString(RawByteString(sStream.Datastring));
except
sStream.Free;
end;
finally
sStream.Free;
end;
end;
finally
AData.Free;
end;
finally
Header.Free;
end;
finally
InternetCloseHandle(pRequest);
end;
finally
InternetCloseHandle(pConnection);
end;
finally
InternetCloseHandle(pSession);
end;
end;
这是我尝试过的其他方法之一,这个也给出了同样的错误:
function TDelphiCommand.ExecutePost(const URL, Data: string): string;
type
PMemArray = ^TMemArray;
TMemArray = array [0..0] of byte;
var
RespStream: TMemoryStream;
ResBytes: TBytes;
aPointer: PMemArray;
PostStream: TStringStream;
S: string;
begin
Result := '{"value":""}';
PostStream := TStringStream.Create(Data, TEncoding.UTF8);
RespStream := TMemoryStream.Create;
try
PostStream.WriteString(Data);
PostStream.Position := 0;
RespStream.Size := 0;
RespStream.Position := 0;
InitHeader;
Fhttp.Request.ContentLength := PostStream.Size;
try
// Fhttp.Post(URL, PostStream, aResponseStream);
Fhttp.Post(URL, PostStream, RespStream);
RespStream.Seek(0, soFromBeginning);
aPointer := HeapAlloc(GetProcessHeap, 0, Fhttp.Response.ContentLength);
RespStream.Read(aPointer^, Fhttp.Response.ContentLength);
SetLength(ResBytes, Fhttp.Response.ContentLength);
RespStream.Read(aPointer, Fhttp.Response.ContentLength);
// VirtualProtect(@NOP_Proc, FSizeOfNOP_Proc, PAGE_EXECUTE_READWRITE, @c1);
if PByte(ResBytes)^ > 0 then
Result := TEncoding.UTF8.GetString(ResBytes);
Debug_Log(Result);
except
Debug_Log('ExecuteGet POST: ' + Result);
// Result := 'Disconnected!';
FreeAndNil(PostStream);
FreeAndNil(PostStream);
FreeAndNil(RespStream);
FreeAndNil(RespStream);
end;
finally
if Assigned(PostStream) then
FreeAndNil(PostStream);
if Assigned(RespStream) then
FreeAndNil(RespStream);
end;
end;
【问题讨论】:
-
你的 AV 在哪一行?当您尝试分配给结果时?顺便提一下 - 在源代码的第一个变体中 - 您将尝试双重释放 sStream 以防出现异常,只是一个旁注。
-
你说的AV是什么意思?这是设置结果的行:
Result := sStream.Datastring;当它因访问冲突而中断时,DataString 有一个值,但结果为空, -
用 UTF8 字节创建一个字节数组然后将其写入内存流以传递指向字节的指针也有点奇怪。只需创建字节数组,就有指向字节的指针。这里有太多无关的代码,我无法深入挖掘。
-
我不是质疑你是否需要使用UTF8,我只是指出你做错了。
-
@Gimmly 在您的 Indy 代码中,您将
Data写入TStringStream两次。并双重释放流。但更重要的是,Post()之后的所有代码都是错误的,太过分了,而且没有必要。Post()有一个返回字符串的重载,如果服务器声称数据使用 UTF-8,它将为您处理 UTF-8 解码:Result := Fhttp.Post(URL, PostStream);
标签: delphi