- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
基本上,我使用 Chromium 来显示一个我无法控制的网站。当用户点击特定按钮时,会发送 XHR 请求;我希望能够找到答案。因此,假设请求发送 A,服务器回复 B;我希望能够阅读 B。我该怎么做?
最佳答案
在旧的 CEF1 中,您可以简单地使用 OnResourceResponse
事件。在 CEF3 中,这样一个看似微不足道的任务可能会成为一个真正的挑战,因为 Issue 515
中链接的 the answer
与您在这里提出的基本相同的问题仍然处于打开状态,并且似乎(此时)唯一的方法是实现您自己的 CefResourceHandler
处理程序在浏览器和外部世界之间建立代理。实现原理在similar topic
中描述如下:
You can use CefResourceHandler via CefRequestHandler::GetResourceHandler and execute the request/return the response contents yourself using CefURLRequest.
所以这是在 DCEF3 中要做的事情(此时):
首先派生您自己的 TCefResourceHandlerOwn
后代,其中至少实现以下方法:
ProcessRequest
- 在这里您将转发(发送)请求 A 到服务器并接收服务器的响应 B(这是您第一次使用响应数据 B 的机会),您应该这样做保持存储(最好保存在类字段中,以便可以轻松地将其刷新到 ReadResponse
方法的输出缓冲区)。
GetResponseHeaders
- 在此方法中,您需要填写有关响应 B 数据长度和(部分) header 字段的输出参数(这可能是您需要解析响应 B 的位置)用于填充 CefResponse
类型参数成员的 header )。
ReadResponse
- 您将在此处刷新响应 B 数据,以便浏览器进行最终处理。
下一步是将您自己的资源处理程序分配给请求。从技术上讲,这就像从 Chromium 的 OnGetResourceHandler
事件处理程序返回对资源处理程序接口(interface)的引用一样简单。但在这一步中,您应该考虑到,您越缩小标准,您的资源处理程序就越简单。因为如果你分配你的处理程序,例如对于任何请求(针对任何 URL),那么您可能必须处理并过滤掉来自与您的整体任务绝对无关的服务器的响应。
因此,我建议将分配范围缩小到由该 Web 应用程序按钮生成的请求,或者至少按请求资源类型(在本例中为 RT_XHR
)生成的请求,这样您就不会'不需要自己处理所有请求。
实现上述步骤的方法有很多种。在此示例中,我插入了 Chromium 浏览器类,并添加了一个新事件 OnXmlHttpExchange
,该事件在 XHR 请求完成时触发(但在它传递到浏览器之前,这甚至允许您修改响应)。
uses
CefLib, CefVCL;
type
TXmlHttpExchangeEvent = procedure(Sender: TObject; const Request: ICefRequest; const Response: ICefResponse; DataStream: TMemoryStream) of object;
TChromium = class(CefVCL.TChromium)
private
FOnXmlHttpExchange: TXmlHttpExchangeEvent;
protected
procedure DoXmlHttpExchange(const Request: ICefRequest; const Response: ICefResponse; DataStream: TMemoryStream); virtual;
function doOnGetResourceHandler(const Browser: ICefBrowser; const Frame: ICefFrame; const Request: ICefRequest): ICefResourceHandler; override;
public
property OnXmlHttpExchange: TXmlHttpExchangeEvent read FOnXmlHttpExchange write FOnXmlHttpExchange;
end;
TXmlHttpHandler = class(TCefResourceHandlerOwn)
private
FOwner: TChromium;
FOffset: NativeUInt;
FStream: TMemoryStream;
FCallback: ICefCallback;
FResponse: ICefResponse;
protected
function ProcessRequest(const Request: ICefRequest; const Callback: ICefCallback): Boolean; override;
procedure GetResponseHeaders(const Response: ICefResponse; out ResponseLength: Int64; out RedirectUrl: ustring); override;
function ReadResponse(const DataOut: Pointer; BytesToRead: Integer; var BytesRead: Integer; const Callback: ICefCallback): Boolean; override;
public
constructor Create(Owner: TChromium; const Browser: ICefBrowser; const Frame: ICefFrame; const SchemeName: ustring; const Request: ICefRequest); reintroduce;
destructor Destroy; override;
procedure WriteResponse(const Request: ICefUrlRequest; Data: Pointer; Size: NativeUInt); virtual;
procedure CompleteRequest(const Request: ICefUrlRequest); virtual;
end;
TXmlHttpRequestClient = class(TCefUrlrequestClientOwn)
private
FHandler: TXmlHttpHandler;
protected
procedure OnDownloadData(const Request: ICefUrlRequest; Data: Pointer; DataLength: NativeUInt); override;
procedure OnRequestComplete(const Request: ICefUrlRequest); override;
public
constructor Create(Handler: TXmlHttpHandler); reintroduce;
end;
implementation
{ TChromium }
procedure TChromium.DoXmlHttpExchange(const Request: ICefRequest; const Response: ICefResponse; DataStream: TMemoryStream);
begin
// fire the OnXmlHttpExchange event
if Assigned(FOnXmlHttpExchange) then
FOnXmlHttpExchange(Self, Request, Response, DataStream);
end;
function TChromium.doOnGetResourceHandler(const Browser: ICefBrowser; const Frame: ICefFrame; const Request: ICefRequest): ICefResourceHandler;
begin
// first trigger the browser's OnGetResourceHandler event
Result := inherited;
// if no handler was assigned and request is of type XHR, create our custom one
if not Assigned(Result) and (Request.ResourceType = RT_XHR) then
Result := TXmlHttpHandler.Create(Self, Browser, Frame, 'XhrIntercept', Request);
end;
{ TXmlHttpHandler }
constructor TXmlHttpHandler.Create(Owner: TChromium; const Browser: ICefBrowser; const Frame: ICefFrame; const SchemeName: ustring; const Request: ICefRequest);
begin
inherited Create(Browser, Frame, SchemeName, Request);
FOwner := Owner;
FStream := TMemoryStream.Create;
end;
destructor TXmlHttpHandler.Destroy;
begin
FStream.Free;
inherited;
end;
function TXmlHttpHandler.ProcessRequest(const Request: ICefRequest; const Callback: ICefCallback): Boolean;
begin
Result := True;
// reset the offset value
FOffset := 0;
// store the callback reference
FCallback := Callback;
// create the URL request that will perform actual data exchange (you can replace
// it with any other; e.g. with MSXML, or an Indy client)
TCefUrlRequestRef.New(Request, TXmlHttpRequestClient.Create(Self));
end;
procedure TXmlHttpHandler.GetResponseHeaders(const Response: ICefResponse; out ResponseLength: Int64; out RedirectUrl: ustring);
var
HeaderMap: ICefStringMultimap;
begin
// return the size of the data we have in the response stream
ResponseLength := FStream.Size;
// fill the header fields from the response returned by the URL request
Response.Status := FResponse.Status;
Response.StatusText := FResponse.StatusText;
Response.MimeType := FResponse.MimeType;
// copy the header map from the response returned by the URL request
HeaderMap := TCefStringMultimapOwn.Create;
FResponse.GetHeaderMap(HeaderMap);
if HeaderMap.Size <> 0 then
FResponse.SetHeaderMap(HeaderMap);
end;
function TXmlHttpHandler.ReadResponse(const DataOut: Pointer; BytesToRead: Integer; var BytesRead: Integer; const Callback: ICefCallback): Boolean;
begin
// since this method can be called multiple times (reading in chunks), check if we
// have still something to transfer
if FOffset < FStream.Size then
begin
Result := True;
BytesRead := BytesToRead;
// copy the data from the response stream to the browser buffer
Move(Pointer(NativeUInt(FStream.Memory) + FOffset)^, DataOut^, BytesRead);
// increment the offset by the amount of data we just copied
Inc(FOffset, BytesRead);
end
else
Result := False;
end;
procedure TXmlHttpHandler.WriteResponse(const Request: ICefUrlRequest; Data: Pointer; Size: NativeUInt);
begin
// write the just downloaded data to the intermediate response stream
FStream.Write(Data^, Size);
end;
procedure TXmlHttpHandler.CompleteRequest(const Request: ICefUrlRequest);
begin
FStream.Position := 0;
// store the response reference for the GetResponseHeaders method
FResponse := Request.GetResponse;
// this method is executed when the URL request completes, so we have everything we
// need to trigger the OnXmlHttpExchange event
FOwner.DoXmlHttpExchange(Request.GetRequest, FResponse, FStream);
// this signals the handler that the request has completed and that it can process
// the response headers and pass the content to the browser
if Assigned(FCallback) then
FCallback.Cont;
end;
{ TXmlHttpRequestClient }
constructor TXmlHttpRequestClient.Create(Handler: TXmlHttpHandler);
begin
inherited Create;
FHandler := Handler;
end;
procedure TXmlHttpRequestClient.OnDownloadData(const Request: ICefUrlRequest; Data: Pointer; DataLength: NativeUInt);
begin
FHandler.WriteResponse(Request, Data, DataLength);
end;
procedure TXmlHttpRequestClient.OnRequestComplete(const Request: ICefUrlRequest);
begin
FHandler.CompleteRequest(Request);
end;
以及这个插入类的可能用法:
type
TForm1 = class(TForm)
Chromium: TChromium;
procedure FormCreate(Sender: TObject);
private
procedure XmlHttpExchange(Sender: TObject; const Request: ICefRequest; const Response: ICefResponse; DataStream: TMemoryStream);
end;
implementation
procedure TForm1.FormCreate(Sender: TObject);
begin
Chromium.OnXmlHttpExchange := XmlHttpExchange;
end;
procedure TForm1.XmlHttpExchange(Sender: TObject; const Request: ICefRequest; const Response: ICefResponse; DataStream: TMemoryStream);
begin
// here you can find the request for which you want to read the response (explore the
// Request parameter members to see by what you can do this)
if Request.Url = 'http://example.com' then
begin
// the DataStream stream contains the response, so process it here as you wish; you
// can even modify it here if you want
DataStream.SaveToFile(...);
end;
end;
关于delphi - 如何检索 XHR 响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30406803/
这可能是一个非常明显的问题,但请解释一下 xhr 和 xhr.upload 之间的区别是什么? 我的用例是我正在将文件上传到服务器,但假设服务器出现故障。在这种情况下,我应该处理 xhr.onerro
这是我的场景: 我有一个 URL,可以生成管理工作区的大量导出 - 它通常约为 3mb,需要约 15 秒才能生成。 当前的实现是对按钮上带有 download 属性的 URL 的正常同步请求,以强制下
我正在执行 XMLHttpRequest,如果失败,我想回退到执行其他操作(读取本地文件),但我想在 XHR 函数 (getDBfileXHR) 本身之外执行此操作。 我也在使用 Jquery。 考虑
XMLHttpRequest 实例上有五个事件。 var xhr = new XMLHttpRequest(); xhr.onloadstart = res => { console.log(
xhr.open('put',url,false) xhr.upload.addEventListener('load',function(e){alert(xhr.responseText)},fa
我正在尝试 promisify the native XHR , 现在问题来了,当我使用下面的代码时: function request(method, url) { return new P
我想知道.. 我怎样才能得到 XHR finished loading 字符串? 基本上,我在 Google instant 的页面上,我想以字符串的形式返回搜索结果的“真实”URL。 最佳答案 如果
是否可以在 XMLHttpRequest 的 onreadystatechange 处理程序中找到作为参数发送到 XMLHttpRequest 的 send(data) 函数的数据?我认为此时它必须存
当我在 xhr.then() 中返回“结果”并且我使用 dojo 1.10.4 时遇到一些问题,请帮助我! 以下代码在dojo中使用xhr('dojo/request/xhr')连接到API: rem
这个问题在这里已经有了答案: How to structure nested Promises (3 个答案) 关闭 6 年前。 我需要做一个 promise 序列。我想使用基于标准的方法(ES6?
当执行“GET”请求时,xhr.response 和 xhr.responseText 都返回相同的值。有什么不同?有吗? 最佳答案 response 被解释为 ArrayBuffer、Blob、Do
我只需要支持主要的现代浏览器(IE10+、FF、Chrome、Safari) 我可以做这个替换吗,因为我想简化我的代码库: 来自: xhr.onreadystatechange = function
DataTables 版本:1.10.20 我目前正在使用 pipeline plugin并聆听 xhr event 。 xhr 事件按预期触发,但是回调中的 xhr 参数未定义。设置对象中还有一个
在非常高的级别上,我们单击一个命令建筑物控制点的按钮;打开或关闭灯。单击应该向服务器发送 POST 请求。问题是有时单击按钮但 POST 请求不会发出。该按钮没有指示它是否已被单击的功能(小幅增强)。
我正在尝试使用 youtube v3 API 上传视频,查看 this示例。 所以,我写了这样的东西: var xhr = new XMLHttpRequest(); xhr.open('PUT',
我正在使用 XHR GET 获取 Blade html 并尝试缓存它,这样它就不需要每次都去服务器下载它。这是我的代码。 但这不起作用并且总是转到服务器。 $.ajax({ method: "
我正在尝试为文件上传创建一个进度条,但由于某种原因,XHR 进度响应仅在最后触发一次。但是,如果我打开 firebug 窗口,它可以 100% 正常工作(在文件上传过程中触发)。我正在本地主机上测试它
我正在尝试获取 xhr 请求。 (该脚本应每 2 秒循环运行一次)这是我的脚本: function getJson() { var xhr = new XMLHttpReque
我有一个简单的 XHR 来加载“testdirectory/testpage.html” var xhr; (XMLHttpRequest) ? xhr= new XMLHttpRequest() :
我正在使用XHR npm 上的 lib 用于在 JS 应用程序的客户端发出 ajax 请求。我的代码如下所示: xhr({uri: "http://foo"},function (err, resp,
我是一名优秀的程序员,十分优秀!