HTML5——XMLHttpRequest 2:基于Node.js的用户修改头像

这篇博客介绍了如何使用HTML5的XMLHttpRequest 2特性,结合Node.js和相关库,实现用户修改头像的功能。内容包括Node.js环境配置、项目初始化、框架安装、路由配置、页面实现以及详细步骤。在实现过程中,需要注意数据类型匹配和错误处理,如400 Bad Request错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Day13

今日份内容:使用XMLHttpRequest 2制作基于Node.js的用户修改头像

在HTML5规范中对XMLHttpRequest对象的send()方法进行改良后,其可以发送字符串、document对象、表单数据、Blob对象、文件以及ArrayBuffer对象。

XMLHttpRequest 2

  • 了解XMLHttpRequest与服务器异步交互
  • 使用XMLHttpRequest向服务器提交数据

内容

  1. 配置Node.js环境
  2. 项目初始化
  3. 安装body-parser、connect-multiparty、express框架
  4. 路由配置实现
  5. 页面实现

代码

//项目的文件入口,包含路由配置等。
var express = require('express');
//connect-multiparty用于解决文件上传问题
var mutipart = require('connect-multiparty');

var mutipartMiddeware = mutipart();
var app = express();
//将静态文件目录设置为"根目录+/public"
app.use(express.static('public'));
//修改临时文件储存位置
app.use(mutipart({
	uploadDir: './public/uploadFolder'
}));
//设置HTTP服务监听的端口号
app.set('port', process.env.PORT || 3000);
app.listen(app.get('port'), function() {
	console.log("Express started on localhost:" + app.get('port') + '; press Ctrl-C to terminate.');
});
//以下为路由配置
//1.当访问localhost:3000时。默认访问的页面
app.get('/', function(req, res) {
	res.type('text/html');
	res.sendFile(__dirname + '/HTML5Camera&Upload.html');
});
//2.当用户使用post方式提交表单到/upload服务时,读取表单内容并将文件上传
app.post('/upload', mutipartMiddeware, function(req, res) {
	console.log(req.body.name + "\n=========\n");
	//这里打印可以看到接收文件的信息
	console.log(req.files.file.path + "\n=========\n");
	var jsonObject = {};
	//默认路径为:public\uploadFolder\aYm65V_E0Zn1ho5lDd,需要将public\部分去掉
	var path = req.files.file.path;
	path = path.substring(path.indexOf("\\"));
	console.log(path);
	jsonObject.image = path;
	jsonObject.msg = "文件上传成功!"
	//给浏览器返回成功提示
	res.send(jsonObject);
});

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>拍照上传</title>
		<link rel="stylesheet" type="text/css" href="styles/css/main.css" />
	</head>
	<body>
		<div class="container">
			<div class="header">
				<div class="head-img">
					<img id="uploadImage" src="styles/images/pdx2.jpeg">
					<div class="button_border margin-t">编辑头像</div>
				</div>
			</div>
			<div class="content">
				<ul class="nav">
					<li>我的主页</li>
					<li><span class="selected">个人资料</span></li>
					<li>相册</li>
					<li>分享</li>
					<li>日志</li>
					<li>好友</li>
				</ul>
				<div class="position">
					<span class="arrow"></span>当前所在位置:我的主页>>
					<span class="green">个人资料</span>
				</div>
				<h3>修改头像</h3>
				<form action="UploadServlet" method="post" enctype="multipart/form-data" id="uploadForm">
					<div class="left">
						<div class="gray_box">
							<!-- <video id="video" autoplay="autoplay"></video> -->
							<img src="styles/images/pdx1.jpeg" width="400" height="300">
						</div>
						<p><span>头像上传:</span>
							<input type="file" id="headImage" onchange="changeHeadImage()" />
						</p>
						<p><span>头像描述:</span>
							<textarea rows="3" cols="30"></textarea>
						</p>
						<div class="save">
							<span class="button_border">取消</span>
							<span class="button_blue" onclick="sendForm()">保存</span>
						</div>
					</div>
					<div class="right">
						<p>拍照效果:<br><br></p>
						<div class="photo" id="box">
							<canvas id="canvas" width="400" height="300"></canvas>
							<div id="shade"></div>
						</div>
						<div id="">
							<span id="reSnap" class="button_border">拍照</span>
						</div>
						拍照截图效果:<br>
						<div class="cutPhoto">
							<canvas id="cutCanvas" width="200" height="200"></canvas>
						</div>
					</div>
				</form>
			</div>
		</div>
		<div class="footer">学习之路,亦是孤独;愿君砥砺,求败独孤</div>
		<script type="text/javascript">
			//获得Canvas对象
			var canvas = document.getElementById("canvas");
			var cutCanvas = document.getElementById("cutCanvas");
			var context = canvas.getContext("2d");
			var cutContext = cutCanvas.getContext("2d");
			//获得video摄像头区域
			var video = document.getElementById("video");
			var shade = document.getElementById("shade");
			var box = document.getElementById("box");
			var reSnap = document.getElementById("reSnap");
			//阴影区域左上角的x,y坐标
			var shadeX, shadeY;
			//当DOM树构建完成时的时候就会执行DOMContentLoaded事件
			window.addEventListener("DOMContentLoaded", function() {
				//兼容主流浏览器
				navigator.getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator
					.mozGetUserMedia || navigator.msGetUserMedia;
				//从摄像头读取视频流,并在video中显示
				navigator.getMedia({
						video: true,
						audio: false
					},
					//读取成功,对视频进行处理
					function(stream) {
						if (navigator.mozGetUserMedia) {
							video.mozSrcObject = stream;
						} else {
							var vendorURL = window.URL || window.webkitURL;
							video.src = vendorURL.createObjectURL(stream);
						}
						video.play();
					},
					//读取失败时所调用的回调函数
					function(err) {
						console.log("错误信息:" + err);
					});
			}, false);
			//从视频中抓拍照片
			reSnap.onclick = function() {
				context.drawImage(video, 0, 0, 400, 300);
				init();
				shade.style.display = "none";
			}
			//绑定鼠标移动触发的事件
			function init() {
				box.onmouseout = function(ev) {
					document.body.style.cursor = "";
				}
				box.onmousemove = function(ev) {
					//设定鼠标样式
					document.body.style.cursor = "move";
					//获取box对象的左侧到浏览器窗口左侧的距离
					var boxX = getLeft(box);
					//获取box对象的顶部到浏览器窗口顶部的距离
					var boxY = getTop(box);
					//计算阴影区域的左上角x的坐标
					shadeX = ev.pageX - boxX - 100;
					//计算阴影区域的左上角y的坐标
					shadeY = ev.pageY - boxY - 100;
					//防止阴影区移到图片之外
					if (shadeX < 0) {
						shadeX = 0;
					} else if (shadeX > 0) {
						shadeX = 200;
					}
					if (shadeY < 0) {
						shadeY = 0;
					} else if (shadeY > 0) {
						shadeY = 100;
					}
					shade.style.display = "block";
					shade.style.left = shadeX + "px";
					shade.style.top = shadeY + "px";
				}
			}
			init();
			box.onclick = function() {
				//将box的onmosemove事件清空
				box.onmousemove = function() {

				};
				cutContext.drawImage(canvas, shadeX, shadeY, 200, 200, 0, 0, 200, 200);
				shadeX = 0;
				shadeY = 0;
			}
			//获取元素的纵坐标(相对于body)
			function getTop(e) {
				var offset = e.offsetTop;
				if (e.offsetParent != null) {
					offset += getTop(e.offsetParent);
				}
				return offset;
			}
			//获取元素的横坐标(相对于body)
			function getLeft(e) {
				var offset = e.offsetLeft;
				if (e.offsetParent != null) {
					offset += getLeft(e.offsetParent);
				}
				return offset;
			}
			//用于提交表单
			function sendForm() {
				var data = cutCanvas.toDataURL();
				data = data.split(',')[1];
				data = window.atob(data);
				var ia = new Uint8Array(data.length);
				for (var i = 0; i < data.length; i++) {
					ia[i] = data.charCodeAt(i);
				}
				//canvas.toDataURL返回的默认格式是image/png
				var blob = new Blob([ia], {
					type: "image/jpg"
				});
				//创建FormData对象,用于封装表单数据
				var formData = new FormData(document.getElementById('uploadForm'));
				formData.append('file', blob);
				var xhr = new XMLHttpRequest();
				//请求URL
				xhr.open('POST', 'upload');
				xhr.responseType = "json";
				xhr.send(formData);
				xhr.onload = function(event) {
					if (xhr.status == 200) {
						var json = xhr.response;
						document.getElementById("uploadImage").src = json.image;
						console.log(json.image);
						context.fillStyle = "#FFFFFF";
						context.fillRect(0, 0, canvas.width, canvas.height);
						cutContext.fillStyle = "#ffffff";
						cutContext.fillRect(0, 0, cutCanvas.width, cutCanvas.height);
						shade.style.display = "none";
					} else {
						alert('保存出错了');
					}
				}
			}
			//用于加载本地图像文件
			function changeHeadImage() {
				var file = document.getElementById("headImage");
				if (window.FileReader) {
					var fr = new FileReader();
					fr.onloadend = function(e) {
						var image = new Image();
						image.src = e.target.result;
						image.onload = function() {
							context.drawImage(image, 0, 0, 400, 300);
						};
					};
					fr.readAsDataURL(file.files[0]);
				}
			}
		</script>
	</body>
</html>

结果

在这里插入图片描述

步骤详解

  1. 控制台使用npm init命令对项目初始化

  2. 控制台分别使用 npm install body-parse --save-dev 命令、npm install connect-multiparty --save-dev 命令来安装Express框架、npm install express --save-dev 命令来安装body-parse、connect-multiparty、express框架
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  3. 第1,2步配置完成后package.json文件内容如下
    在这里插入图片描述

  4. 目录结构
    在这里插入图片描述

  5. 创建app.js作为项目文件入口,里面编写路由配置等信息

  6. 完成HTML5Camera&Upload.html页面编写

  7. 最后在控制台中使用 node app.js 命令启动Node.js服务器,在浏览器中输入 localhost:3000 网址进入测试。

PS

  • 使用require()方法来加载express和connect-multiparty两个框架,其中express框架作为服务端的路由,根据用户的url请求分配到相应的应用程序

  • connect-multiparty用于实现用户文件上传功能

  • 当用户以post方式访问"/upload/"路径请求时,服务端将对用户提交的头像和描述信息进行处理,并返回一个JSON数据。

  • 运行过程中出现了参数类型报错,请注意查看FormData数据传递的类型是否正确。
    在这里插入图片描述

  • 运行过程中出现:400 (Bad Request)报错,请主义查看页面间提交的数据是否为同一类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

is_Del

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值