ajax UIWebViewDelegate 不监控 XMLHttpRequest?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5353278/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIWebViewDelegate not monitoring XMLHttpRequest?
提问by Thizzer
Is it true that the UIWebViewDelegate does not monitor requests made by using a XMLHttpRequest? If so, is there a way to monitor these kind of requests?
UIWebViewDelegate 不监视使用 XMLHttpRequest 发出的请求是真的吗?如果是这样,有没有办法监控这些类型的请求?
e.g. UIWebViewDelegate does not catch this in -(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSMutableURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
例如 UIWebViewDelegate 没有抓住这个-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSMutableURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.google.com", true);
xhr.onreadystatechange=function()
{
if (xhr.readyState==4)
{
alert(xhr.responseText);
}
}
xhr.send();
回答by Mikey
Interesting question.
有趣的问题。
There are two parts to make this work: a JavaScript handler and UIWebView delegate methods. In JavaScript, we can modify prototype methods to trigger events when an AJAX request is created. With our UIWebView delegate, we can capture these events.
有两个部分可以完成这项工作:JavaScript 处理程序和 UIWebView 委托方法。在 JavaScript 中,我们可以修改原型方法以在创建 AJAX 请求时触发事件。使用我们的 UIWebView 委托,我们可以捕获这些事件。
JavaScript Handler
JavaScript 处理程序
We need to be notified when an AJAX request is made. I found the solution here.
我们需要在发出 AJAX 请求时得到通知。我在这里找到了解决方案。
In our case, to make the code work, I put the following JavaScript in a resource called ajax_handler.jswhich is bundled with my app.
在我们的例子中,为了使代码工作,我将以下 JavaScript 放在一个名为ajax_handler.js的资源中,该资源与我的应用程序捆绑在一起。
var s_ajaxListener = new Object();
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;
s_ajaxListener.callback = function () {
window.location='mpAjaxHandler://' + this.url;
};
XMLHttpRequest.prototype.open = function(a,b) {
if (!a) var a='';
if (!b) var b='';
s_ajaxListener.tempOpen.apply(this, arguments);
s_ajaxListener.method = a;
s_ajaxListener.url = b;
if (a.toLowerCase() == 'get') {
s_ajaxListener.data = b.split('?');
s_ajaxListener.data = s_ajaxListener.data[1];
}
}
XMLHttpRequest.prototype.send = function(a,b) {
if (!a) var a='';
if (!b) var b='';
s_ajaxListener.tempSend.apply(this, arguments);
if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a;
s_ajaxListener.callback();
}
What this will actually do is change the location of the browser to some made up URL scheme (in this case, mpAjaxHandle) with info about the request made. Don't worry, our delegate with catch this and the location won't change.
这实际上所做的是将浏览器的位置更改为一些组合的 URL 方案(在本例中为mpAjaxHandle),其中包含有关所发出请求的信息。别担心,我们的代表抓住了这个,位置不会改变。
UIWebView Delegate
UIWebView 委托
First, we need to read our JavaScript file. I suggest doing storing it in a static variable. I'm in the habit of using +initialize.
首先,我们需要阅读我们的 JavaScript 文件。我建议将其存储在静态变量中。我习惯使用+initialize。
static NSString *JSHandler;
+ (void)initialize {
JSHandler = [[NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ajax_handler" withExtension:@"js"] encoding:NSUTF8StringEncoding error:nil] retain];
}
Next, we want to inject this JavaScript before a page is done loading so we can receive all events.
接下来,我们希望在页面加载完成之前注入此 JavaScript,以便我们可以接收所有事件。
- (void)webViewDidStartLoad:(UIWebView *)webView {
[webView stringByEvaluatingJavaScriptFromString:JSHandler];
}
Finally, we want to capture the event.
最后,我们要捕获事件。
Since the URL Scheme is made up, we don't want to actually follow it. We return NOand all is well.
由于 URL Scheme 是组成的,我们不想实际遵循它。我们返回NO,一切都很好。
#define CocoaJSHandler @"mpAjaxHandler"
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([[[request URL] scheme] isEqual:CocoaJSHandler]) {
NSString *requestedURLString = [[[request URL] absoluteString] substringFromIndex:[CocoaJSHandler length] + 3];
NSLog(@"ajax request: %@", requestedURLString);
return NO;
}
return YES;
}
I created a sample project with the solution but have nowhere to host it. You can message me if you can host it and I'll edit this post accordingly.
我使用该解决方案创建了一个示例项目,但无处可托管。如果你可以主持它,你可以给我留言,我会相应地编辑这篇文章。
回答by George
You can use an NSURLProtocol. For instance if you call XMLHttpRequest with http://localhost/pathyou can handle it with the following:
您可以使用 NSURLProtocol。例如,如果您使用 XMLHttpRequest 调用,http://localhost/path您可以使用以下方法处理它:
@interface YourProtocol: NSURLProtocol
Then for the implementation:
然后为实现:
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
return [request.URL.host isEqualToString:@"localhost"];
}
+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request
{
return request;
}
- (void) startLoading
{
// Here you handle self.request
}
- (void)stopLoading
{
}
You need to register the protocol as follows:
您需要按如下方式注册协议:
[NSURLProtocol registerClass:[YourProtocol class]];
回答by terrinecold
By implementing and registering a subclass of NSURLProtocol you can capture all the request from your UIWebView. It may be overkill in some cases but if you are not able to modify the javascript actually being run it is your best bet.
通过实现和注册 NSURLProtocol 的子类,您可以捕获来自 UIWebView 的所有请求。在某些情况下,这可能有点矫枉过正,但如果您无法修改实际运行的 javascript,那么这是您最好的选择。
In my case I need to capture all the request and insert a specific HTTP header to every one of them. I have done this by implementing NSURLProtocol, registering it using registerClass and answering YES in my subclass to + (BOOL)canInitWithRequest:(NSURLRequest *)request if the request corresponds to the URLs I am interested in. You then have to implement the other methods of the protocol this can be done by using an NSURLConnection, setting the protocol class as the delegate and redirecting the delegate methods of NSURLConnection to NSURLProtocolClient
在我的情况下,我需要捕获所有请求并向每个请求插入一个特定的 HTTP 标头。我通过实现 NSURLProtocol,使用 registerClass 注册它并在我的子类中回答 YES 到 + (BOOL)canInitWithRequest:(NSURLRequest *)request 如果请求对应于我感兴趣的 URL 来做到这一点。然后你必须实现其他方法这可以通过使用 NSURLConnection 来完成,将协议类设置为委托并将 NSURLConnection 的委托方法重定向到 NSURLProtocolClient
回答by Anomie
It does appear to be true. There is no way to monitor what a UIWebView is doing beyond what UIWebViewDelegate provides, unless perhaps you can figure out a way to use stringByEvaluatingJavaScriptFromString:to inject some Javascript to do what you need.
这似乎是真的。除了 UIWebViewDelegate 提供的功能之外,无法监控 UIWebView 正在做什么,除非您可能想出一种方法stringByEvaluatingJavaScriptFromString:来注入一些 Javascript 来执行您需要的操作。
回答by Soyoes
As other peoples mentioned, UIWebViewDelegate observes changes of window.location and iframe.src only.
正如其他人提到的, UIWebViewDelegate 只观察 window.location 和 iframe.src 的变化。
In case that you just want to use custom url scheme of iOS only,
you can take advantage of <iframe>like this way.
如果您只想使用 iOS 的自定义 url 方案,您可以使用<iframe>这种方式。
For example, if you want to call a URL Scheme like this
例如,如果你想像这样调用一个 URL Scheme
objc://my_action?arg1=1&arg2=2
in your js file:
在你的 js 文件中:
/**
* @param msg : path of your query
* @param data : arguments list of your query
*/
var call_url = function(msg, data){
const scheme = "objc";
var url = scheme + '://' + msg;
if(data){
var pstr = [];
for(var k in data)
if(typeof data[k] != 'function')
pstr.push(encodeURIComponent(k)+"="+encodeURIComponent(data[k]));
url += '?'+pstr.join('&');
}
var i = document.createElement("iframe");
i.src = url;
i.style.opacity=0;
document.body.appendChild(i);
setTimeout(function(){i.parentNode.removeChild(i)},200);
}
//when you call this custom url scheme
call_url ("my_action", {arg1:1,arg2:2});

