Javascript 使用AJAX在网页上动态预加载/显示网络摄像头快照
我有一个IP摄像头,可以将实时视频流到我的网站上。问题是,它是由ActiveX控件驱动的。更糟糕的是,此控件没有签名。为了给那些使用IE以外浏览器的人提供一个更安全的选择,或者(理所当然地)不愿意更改他们的安全设置,我正在使用摄像头内置的快照脚本,该脚本提供640x480实时JPEG图像。计划是使用Javascript每隔500毫秒在屏幕上实时更新一次图像,而不必重新加载整个页面 我尝试使用Image()对象预加载图像,并在启动onload时更新Image元素的SRC属性:Javascript 使用AJAX在网页上动态预加载/显示网络摄像头快照,javascript,jquery,ajax,Javascript,Jquery,Ajax,我有一个IP摄像头,可以将实时视频流到我的网站上。问题是,它是由ActiveX控件驱动的。更糟糕的是,此控件没有签名。为了给那些使用IE以外浏览器的人提供一个更安全的选择,或者(理所当然地)不愿意更改他们的安全设置,我正在使用摄像头内置的快照脚本,该脚本提供640x480实时JPEG图像。计划是使用Javascript每隔500毫秒在屏幕上实时更新一次图像,而不必重新加载整个页面 我尝试使用Image()对象预加载图像,并在启动onload时更新Image元素的SRC属性: function u
function updateCam() {
var url = "../snapshot.cgi?t=" + new Date().getTime();
img = new Image();
img.onload = function() {
$("#livePhoto").attr("src", url);
camTimer = setTimeout(updateCam, 500);
}
img.src = url;
}
这工作正常,但很难确定相机何时被禁用,我需要这样做才能优雅地降级。内部快照脚本被设置为在这种情况下返回204(无内容)的HTTP状态代码,当然,我无法使用Image对象检测到这一点。此外,onload事件不是100%可靠的
因此,我使用jQuery(1.2.6版)ajax
函数对URL执行GET请求,并在complete
回调中评估状态代码并相应地设置URL:
function updateCam() {
var url = "../snapshot.cgi?t=" + new Date().getTime();
$.ajax({
type: "GET",
url: url,
timeout: 2000,
complete: function(xhr) {
try {
var src = (xhr.status == 200) ? url : '../i/cam-oos.jpg';
$("#livePhoto").attr("src", src);
}
catch(e) {
JoshError.log(e);
}
camTimer = setTimeout(updateCam, 500);
}
});
}
而且这个效果很好但仅限于IE这是我想回答的问题:为什么这在Firefox或Chrome中不起作用?
complete
事件甚至不会在Firefox中触发。它确实在Chrome中启动,但设置SRC实际上很少加载请求的图像(通常不显示任何内容)。我相信jquery会尝试解释服务器的响应。我相信一些浏览器更能容忍响应解释,所以更严格的浏览器会失败,因为图像不能被视为HTML
解决方案是使用HEAD请求类型而不是GET(类型:“HEAD”)。这样,您仍然可以获得状态响应,而无需抓取图像本身。因此,响应将是空的(不应该把您搞砸)。而且,回复应该快得多。发布第二个答案,因为第一个答案确实不正确。我无法测试此解决方案(因为我无法访问您的网络摄像头脚本),但我建议尝试清理摄像头的响应-因为您显然无法处理原始图像数据,请尝试添加dataFilter设置,如下所示:
function updateCam() {
var url = "../snapshopt.cgi?t=" + new Date().getTime();
$.ajax({
type: "GET",
url: url,
timeout: 2000,
dataFilter : function(data, type) {
return '<div></div>' //so it returns something...
},
complete: function(xhr) {
try {
var src = (xhr.status == 200) ? url : '../i/cam-oos.jpg';
$("#live").attr("src", src);
}
catch(e) {
JoshError.log(e);
}
camTimer = setTimeout(updateCam, 500);
}
});
}
函数updateCam(){
var url=“../snapshopt.cgi?t=“+new Date().getTime();
$.ajax({
键入:“获取”,
url:url,
超时时间:2000,
dataFilter:函数(数据,类型){
return“”//因此它会返回一些内容。。。
},
完成:函数(xhr){
试一试{
var src=(xhr.status==200)?url:“../i/cam oos.jpg”;
$(“#live”).attr(“src”,src);
}
捕获(e){
JoshError.log(e);
}
camTimer=设置超时(updateCam,500);
}
});
}
就像我说的,我还没能测试这个-但它可能允许jquery使用状态码而不会像疯了一样崩溃。好吧,我最终使用了(Eric Pascarello的帽子提示)来测试非IE浏览器。我编写了一个HTTP处理程序(在VB.NET中)来代理IP摄像头并对图像进行base-64编码:
img.onerror = function(){
alert('offline');
}
Imports Common
Imports System.IO
Imports System.Net
Public Class LiveCam
Implements IHttpHandler
Private ReadOnly URL As String = "http://12.34.56.78/snapshot.cgi"
Private ReadOnly FAIL As String = Common.MapPath("~/i/cam-oos.jpg")
Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest
Dim Data As Byte()
With context.Response
.ContentEncoding = Encoding.UTF8
.ContentType = "text/plain"
.Write("data:image/png;base64,")
Try
Using Client As New WebClient()
Data = Client.DownloadData(URL)
End Using
Catch ex As WebException
Data = File.ReadAllBytes(FAIL)
End Try
.Write(Convert.ToBase64String(Data))
End With
End Sub
End Class
然后我只做了一点非IE检测(使用classic document.all检查),以便调用正确的URL/设置正确的SRC:
function updateCam() {
var url = (document.all) ? "../snapshot.cgi?t=" : "../cam.axd?t=";
url += new Date().getTime();
$.ajax({
type: "GET",
url: url,
timeout: 2000,
complete: function(xhr) {
try {
var src;
if(document.all)
src = (xhr.status == 200) ? url : '../i/cam-oos.jpg';
else
src = xhr.responseText;
$("#livePhoto").attr("src", src);
}
catch(e) {
JoshError.log(e);
}
camTimer = setTimeout(updateCam, 500);
}
});
}
非常不幸的是,我不得不求助于这个解决办法。我讨厌浏览器检测代码,也讨厌服务器上的额外负载。代理不仅会迫使我浪费更多的带宽,而且由于代理固有的缺陷以及base-64编码图像所需的时间,它的工作效率也会降低。此外,它并没有设置为像IE那样优雅地降级。尽管我可以重新编写代理以使用HttpWebRequest并返回正确的状态代码,等等。我只是想要尽可能最简单的方法,因为我厌倦了处理这个问题
谢谢大家 使用HEAD给了我更快的响应,但它是404!网络摄像头脚本是自定义HTTP实现吗?不,它内置于IP Cam的内部服务器中,我无法修改它。我可以编写自己的代理,但这解决不了任何问题。回调根本就不会被调用吗?或者它只是不起作用?检查问题的最后一段。运气不好:(在Internet Explorer中,一切都运行得很好。我可能会尝试编写一个代理来包装CGI脚本,并以XML中的base-64编码返回图像。这是一个多么令人头疼的问题啊,我担心我当时没有主意了——显然可能存在一个与javascript无关的潜在问题。这可能是因为至少,网络摄像头没有实现完整的HTTP(转眼)。不确定实现完整HTTP是什么意思。它实现得很好。无论如何,我可以很容易地编写一个代理来返回我想要的任何HTTP。不幸的是,这仍然不能解决问题。谢谢Eric。我确实需要评估状态代码,因为它也可能是304。我需要以不同的方式对这些代码作出反应。另外,一个如前所述,onload事件不可靠。它并不总是触发。我不想设置一个setInterval,以使更新频率取决于连接速度,因此我在load事件(调用被调用方)内执行超时。如果onload由于任何原因从未触发,更新将停止。您能看到我的AJAX方法在Firefox中失败的任何原因吗?是否需要添加另一个QS值来强制它获取它。可能它将它视为缓存,因为您使用AJAX调用调用了它?var src=(xhr.status==200)?url+“&foo=bar”:“../i/cam oos.jpg”;糟糕,我误解了你的评论。我会尝试这样做,但在Fir中根本不会触发“完整”回调