You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带凭证的MJPEG流通过JavaScript的img标签无法加载的技术求助

解决JavaScript携带凭证加载摄像头快照流的问题

问题根源

现代浏览器出于安全规范,已经禁止通过JavaScript代码直接设置包含user:password@格式凭证的URL作为<img>标签的src属性——即使手动在地址栏输入该URL能正常加载,JS操作时浏览器会自动剥离凭证部分,导致请求无权限,图片无法显示。另外你现有代码还存在一个明显错误:motionjpeg_stream函数中,初始获取的src已经是带凭证和协议的完整URL(比如http://user:password@192.168.1.50/snap.jpg),但后续setInterval里又重复拼接http://" + credentials + "@",最终生成的URL会变成http://user:password@http://user:password@192.168.1.50/snap.jpg?xxx,这显然是无效的。


方案1:使用Fetch API获取图片并更新(推荐)

通过Fetch API发起请求并携带凭证,将返回的图片转为Blob URL赋值给<img>,绕过浏览器对URL嵌入凭证的限制。注意需要摄像头支持CORS,或者通过后端代理解决跨域问题。

修改你的motionjpeg_stream函数如下:

function motionjpeg_stream(id, credentials) {
    var image = $(id);
    if (!image.length) return;

    // 提取摄像头的基础URL(去掉初始的协议和凭证,避免重复拼接)
    var baseSrc = image.attr("src").replace(/^http:\/\/.*@/, '');

    // 定时刷新图片
    setInterval(async function() {
        try {
            // 构建请求,通过Headers携带Basic Auth凭证
            const headers = new Headers();
            headers.set('Authorization', 'Basic ' + btoa(credentials));
            
            const response = await fetch(`http://${baseSrc}?${new Date().getTime()}`, {
                method: 'GET',
                headers: headers,
                credentials: 'include' // 携带凭证,根据场景选'include'或'same-origin'
            });

            if (!response.ok) throw new Error('请求失败');
            
            const blob = await response.blob();
            // 先释放之前的Blob URL,避免内存泄漏
            const oldSrc = image.attr("src");
            if (oldSrc.startsWith('blob:')) {
                URL.revokeObjectURL(oldSrc);
            }
            // 生成新的Blob URL赋值给img
            const blobUrl = URL.createObjectURL(blob);
            image.attr("src", blobUrl);
        } catch (err) {
            console.error('加载图片失败:', err);
        }
    }, 1000);
}

同时修改HTML中初始的src设置,去掉凭证部分:

// 原来的代码去掉凭证,只保留摄像头地址和接口
$("img#Camera_MJPEG_stream").attr("src", $.urlParam('ip') + "/snap.jpg"); 

方案2:配置摄像头开启CORS支持

如果你的摄像头支持配置HTTP响应头,添加以下CORS相关头,确保前端请求能正常携带凭证:

  • Access-Control-Allow-Origin: *(或指定你的前端页面域名,更安全)
  • Access-Control-Allow-Credentials: true
  • Access-Control-Allow-Headers: Authorization

配置完成后,方案1的代码就能正常工作。


方案3:后端代理(无CORS支持时使用)

如果摄像头不支持CORS,你可以搭建一个简单的后端代理,前端请求代理服务器,由代理服务器携带凭证去请求摄像头,再将图片返回给前端。

比如用Node.js写一个简单的代理示例(依赖Express和request库):

const express = require('express');
const request = require('request');
const app = express();

app.get('/camera-proxy', (req, res) => {
    const cameraIp = req.query.ip;
    const credentials = 'user:password'; // 可改为动态传入的凭证
    const cameraUrl = `http://${cameraIp}/snap.jpg${req.url.includes('?') ? '&' : '?'}${req.query.t}`;
    
    // 转发请求并携带凭证
    request.get(cameraUrl, {
        auth: {
            user: credentials.split(':')[0],
            pass: credentials.split(':')[1]
        }
    }).pipe(res);
});

app.listen(3000, () => {
    console.log('代理服务器运行在3000端口');
});

然后前端修改请求地址为代理地址:

// 在motionjpeg_stream中修改fetch地址
const response = await fetch(`http://localhost:3000/camera-proxy?ip=${baseSrc.split('/')[0]}&t=${new Date().getTime()}`, {
    method: 'GET',
    credentials: 'same-origin'
});

内容的提问来源于stack exchange,提问作者Vasekdvor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 20:55:36