上期我们完成了相册图片上传,实现图文混排笔记。 但存在使用痛点:临时拍摄素材,必须先拍照保存到相册,再选中文件上传,操作链路偏长。 本次迭代目标:新增拍照上传,调用设备摄像头,拍完直接上传插入笔记。
方案设计
- 后端:Bmob云存储托管图片,无需自建文件服务器,ACL权限隔离,用户仅能查看自己上传图片
- 接口:复用同一个上传接口,相册、拍照上传共用,减少重复代码
- 前端:HTML5原生API唤起后置摄像头,拍摄得到文件,提交接口,图片自动插入Markdown编辑器
后端 Python 核心代码
from flask import Flask, request
from bmob import BmobFile
app = Flask(__name__)
# 相册上传、拍照上传共用一套上传接口
@app.route("/api/upload_img", methods=["POST"])
def upload_img():
img_file = request.files["imgFile"]
current_user_id = request.form.get("current_user")
# 登录权限校验
if not current_user_id:
return {"ok": False, "msg": "用户未登录,请先登录"}
# 上传图片到Bmob云存储
bmob_img = BmobFile(img_file)
bmob_img.save()
img_url = bmob_img.url
return {
"ok": True,
"imgUrl": img_url
}
逻辑很简单:接收前端传过来的图片文件,校验登录态,直接交给Bmob保存,返回图片云端地址给前端。
前端 JS 相机上传代码
// 唤起相机拍照上传
async function uploadFromCamera() {
const cameraInput = document.querySelector("#cameraInput");
// 调用设备后置摄像头
cameraInput.setAttribute('capture','environment');
cameraInput.click();
cameraInput.onchange = async () => {
const photoFile = cameraInput.files[0];
if(!photoFile) return;
const formData = new FormData();
formData.append("imgFile", photoFile);
formData.append("current_user", getUserObjectId());
const resp = await fetch("/api/upload_img",{
method:"POST",
body:formData
})
const resData = await resp.json();
if(resData.ok){
// 插入Markdown图片到编辑器
insertImageToEditor(resData.imgUrl)
}
}
}
// 在编辑器插入图片Markdown
function insertImageToEditor(url){
const markdownImg = ``
editor.insertText(markdownImg)
}
核心:capture="environment" 这个属性,用来唤起设备后置摄像头,拍照后拿到文件对象,和相册文件处理方式完全一致。
效果与安全说明
- 保留原有相册上传入口,双入口共存,按需选用
- 拍照流程:唤起相机 → 拍摄 → 自动上传云端 → 图片直接写入笔记,无需本地保存照片
- 安全:依托Bmob ACL,每个用户的图片资源相互隔离,防止越权访问
项目总结
整个项目全程基于Bmob后端云,省去文件服务器、静态资源托管的开发成本。 从纯文本笔记、相册图文笔记,再到现场拍照上传,循序渐进迭代,很适合作为简历上的Python全栈练手项目。 完整源码已整理,欢迎评论区交流讨论。