如何在JavaScript+HTML+PHP环境中将摄像头捕获的图片上传至服务器
解决摄像头拍摄图片上传服务器的问题
Hey there! 看到你已经搞定了摄像头拍照和展示的功能,这已经迈出一大步啦!现在要把拍好的图片传到服务器对吧?别担心,我来一步步带你完成这个操作,新手也能轻松跟上~
核心思路
你现在通过canvas.toDataURL()得到的是base64格式的字符串,这种格式不仅体积比原始图片大30%左右,服务器处理起来也不太方便。所以我们先把它转换成Blob对象,这是浏览器里专门用来处理二进制文件的类型,更适合上传。
步骤1:实现DataURL转Blob的工具函数
先写一个简单的工具函数,把base64字符串转成Blob:
function dataURLtoBlob(dataurl) { let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], {type:mime}); }
这个函数的作用是拆分dataURL、提取图片格式、解码base64内容,最后生成符合上传要求的Blob对象。
步骤2:添加上传逻辑(推荐用Fetch API)
在你点击拍照的事件处理里,拿到图片的dataURL之后,转成Blob,再用Fetch API发送POST请求到服务器。我已经帮你修改了原代码的点击事件:
click_button.addEventListener('click', async function() { canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height); let image_data_url = canvas.toDataURL('image/jpeg'); dataurl.value = image_data_url; dataurl_container.style.display = 'block'; // 新增上传逻辑 try { // 把dataURL转成Blob let imageBlob = dataURLtoBlob(image_data_url); // 创建FormData对象,模拟表单上传 let formData = new FormData(); // 添加文件到表单:第一个参数是服务器接收的字段名(比如'photo'),第二个是Blob,第三个是文件名 formData.append('photo', imageBlob, 'captured_photo.jpg'); // 发送请求到你的服务器接口,记得替换成实际的URL哦 const response = await fetch('/upload-photo', { method: 'POST', body: formData }); if (response.ok) { const result = await response.json(); alert('上传成功!服务器返回:' + JSON.stringify(result)); } else { throw new Error(`上传失败,状态码:${response.status}`); } } catch (error) { alert(`上传出错:${error.message}`); } });
步骤3:兼容旧浏览器的方案(用XMLHttpRequest)
如果需要支持IE这类老浏览器,可以把Fetch换成XMLHttpRequest,逻辑是一样的:
click_button.addEventListener('click', function() { canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height); let image_data_url = canvas.toDataURL('image/jpeg'); dataurl.value = image_data_url; dataurl_container.style.display = 'block'; // 转成Blob let imageBlob = dataURLtoBlob(image_data_url); let formData = new FormData(); formData.append('photo', imageBlob, 'captured_photo.jpg'); let xhr = new XMLHttpRequest(); xhr.open('POST', '/upload-photo', true); xhr.onload = function() { if (xhr.status === 200) { let result = JSON.parse(xhr.responseText); alert('上传成功!服务器返回:' + JSON.stringify(result)); } else { alert('上传失败,状态码:' + xhr.status); } }; xhr.onerror = function() { alert('上传请求出错'); }; xhr.send(formData); });
完整整合后的代码
这里是把所有功能整合好的完整代码,你可以直接复制使用:
<html> <head> <title>NigraniSof</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"> </head> <body> <button id="start-camera">Start Camera</button> <video id="video" width="320" height="240" autoplay style="display:none;"></video> <button id="click-photo" style="display:none;">Click Photo</button> <div id="dataurl-container" style="display:none;"> <canvas id="canvas" width="320" height="240"></canvas> <div id="dataurl-header">Image Data URL</div> <textarea id="dataurl" readonly></textarea> </div> <script> let camera_button = document.querySelector("#start-camera"); let video = document.querySelector("#video"); let click_button = document.querySelector("#click-photo"); let canvas = document.querySelector("#canvas"); let dataurl = document.querySelector("#dataurl"); let dataurl_container = document.querySelector("#dataurl-container"); // 工具函数:DataURL转Blob function dataURLtoBlob(dataurl) { let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], {type:mime}); } camera_button.addEventListener('click', async function() { let stream = null; try { stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false }); } catch(error) { alert(error.message); return; } video.srcObject = stream; video.style.display = 'block'; camera_button.style.display = 'none'; click_button.style.display = 'block'; }); click_button.addEventListener('click', async function() { canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height); let image_data_url = canvas.toDataURL('image/jpeg'); dataurl.value = image_data_url; dataurl_container.style.display = 'block'; // 上传逻辑 try { let imageBlob = dataURLtoBlob(image_data_url); let formData = new FormData(); formData.append('photo', imageBlob, 'captured_photo.jpg'); // 替换成你的服务器上传接口地址 const response = await fetch('/upload-photo', { method: 'POST', body: formData }); if (response.ok) { const result = await response.json(); alert('上传成功!服务器返回:' + JSON.stringify(result)); } else { throw new Error(`上传失败,状态码:${response.status}`); } } catch (error) { alert(`上传出错:${error.message}`); } }); </script> </body> </html>
几个重要的注意事项
- 替换服务器接口地址:把代码里的
/upload-photo换成你实际的服务器上传API地址,比如http://your-server.com/api/upload-image - 服务器端配置:服务器需要支持接收
multipart/form-data类型的请求,比如用Node.js可以用multer库,PHP可以用$_FILES['photo']来获取上传的文件 - 跨域问题:如果你的前端页面和服务器不在同一个域名下,需要在服务器端配置CORS(跨域资源共享),否则会出现请求失败的错误
内容的提问来源于stack exchange,提问作者Durgesh nandan
相关产品推荐
相关产品推荐

