来访人员登记系统(十)网页端使用websocket向C#服务端传送图片和文字
前置模块
来访人员登记系统(二)网页客户端的实现和websocket通信
本文主要在上文的基础上增加了网页端的图片提交,后台的图片转码处理和发送,服务端的图片复原和保存等功能。
实现思路是使用html的input标签的file类型接收上传的图片,在后台将图片用base64码的形式转成string类型,像发送字符串一样发到服务端,服务端处理好base64码的前缀内容信息,并解码复原图片保存到服务器上。
HTML
HTML在前置模块的基础上增加了input标签,并修改了CSS样式使之布局更加合理。
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>XXXX股份有限公司主机房人员出入申请单</title>
<link rel="stylesheet" href="style.css" />
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<br />
<h1>XXXX股份有限公司</h1>
<h1>主机房人员出入申请单</h1>
<div>
<form id="sendForm">
<table>
<tr>
<td><input id="staff" class="text" type="text" placeholder="弘业对接人员" required /></td>
</tr>
<tr>
<td><input id="name" class="text" type="text" placeholder="外单位人员" required /></td>
</tr>
<tr>
<td><input id="company" class="text" type="text" placeholder="单位名称" required /></td>
</tr>
<tr>
<td><input id="idcard" class="text" type="text" placeholder="身份证号" required pattern="/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/" /></td>
</tr>
<tr>
<td class="imgtext"><span>身份证国徽面照片:</span></td>
</tr>
<tr>
<td><img class="preview" id="preview1"/></td>
</tr>
<tr>
<td><input type="file" accept="image/*" name="img1file" id="img1file" required /></td>
</tr>
<tr>
<td class="imgtext"><span>身份证人像面照片:</span></td>
</tr>
<tr>
<td><img class="preview" id="preview2"/></td>
</tr>
<tr>
<td><input type="file" accept="image/*" name="img2file" id="img2file" required /></td>
</tr>
<tr>
<td><input id="phone" class="text" type="text" placeholder="电话" required /></td>
</tr>
<tr>
<td><span>预约日期:</span><input id="date" class="date" type="date" required /></td>
</tr>
<tr>
<td><input id="ETA" class="text" type="text" placeholder="预期到达时间(hh:mm)" required pattern="^(?:(?:[0-2][0-3])|(?:[0-1][0-9])):[0-5][0-9]$" /></td>
</tr>
<tr>
<td><textarea id="intention" placeholder="进出事由" required></textarea></td>
</tr>
<tr>
<td><textarea id="relevants" placeholder="涉及设备/系统" required></textarea></td>
</tr>
</table>
<br />
<div>
<input class="button" type="submit" value="提交" />
     
<input class="button" type="reset" value="重置" />
</div>
</form>
</div>
<br /><br />
</body>
</html>
CSS
body {
font-family: 'Microsoft YaHei';
text-align: center;
}
table {
margin: 0 auto;
margin-top: 3%;
text-align: center;
font-size: 18px;
width: 15%;
}
td {
padding: 20px 0px 20px 0px;
}
input {
font-size: 18px;
font-family: 'Microsoft YaHei';
}
input.text {
width: 300px;
height: 40px;
}
input.date {
width: 210px;
height: 35px;
}
input.button {
width: 80px;
height: 40px;
}
.imgtext {
text-align: left;
}
.preview {
width: 300px;
height: 200px;
overflow: hidden;
}
#img1file, #img2file {
font-size: 15px;
}
textarea {
font-size: 18px;
font-family: 'Microsoft YaHei';
width: 300px;
height: 100px;
resize: none;
}
Javascript
用fileDom获取文件,自动判断是否为合法的文件类型,并将其显示到界面上的img标签中以供用户预览。
发送时需要先把用户的个人信息发过去,调用一次send()方法,再把两张图片分别发过去,每张图片用FileReader的readAsDataURL方法读取为base64code格式,再把这个字符串发到服务端。
// javascript
var start = function () {
// 上传并预览图片
var fileDom1 = document.getElementById("img1file");
var previewDom1 = document.getElementById("preview1");
var fileDom2 = document.getElementById("img2file");
var previewDom2 = document.getElementById("preview2");
fileDom1.addEventListener("change", e => {
var file = fileDom1.files[0];
// 检查上传的文件是否为图片格式
if (!file || file.type.indexOf("image/") < 0) {
fileDom1.value = "";
previewDom1.src = "";
return;
}
var fileReader = new FileReader();
fileReader.onload = e => {
previewDom1.src = e.target.result;
};
fileReader.readAsDataURL(file);
});
fileDom2.addEventListener("change", e => {
var file = fileDom2.files[0];
if (!file || file.type.indexOf("image/") < 0) {
fileDom2.value = "";
previewDom2.src = "";
return;
}
var fileReader = new FileReader();
fileReader.onload = e => {
previewDom2.src = e.target.result;
};
fileReader.readAsDataURL(file);
});
// 建立websocket通信
var wsImpl = window.WebSocket || window.MozWebSocket;
window.ws = new wsImpl('ws://192.168.204.43:7181/');
var form = document.getElementById('sendForm');
var staff = document.getElementById('staff');
var name = document.getElementById('name');
var company = document.getElementById('company');
var idcard = document.getElementById('idcard');
var phone = document.getElementById('phone');
var date = document.getElementById('date');
var ETA = document.getElementById('ETA');
var intention = document.getElementById('intention');
var relevants = document.getElementById('relevants');
// 以base64格式发送图片文件
function sendFile(fileDom) {
var file = fileDom.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e) {
var base64Code = reader.result;
ws.send(base64Code);
};
}
// 覆写提交事件
form.addEventListener('submit', function (e) {
e.preventDefault();
var msg = staff.value + ',' + name.value + ',' + company.value + ',' + idcard.value + ',' + phone.value + ',' + date.value + ',' + ETA.value + ',' + intention.value + ',' + relevants.value;
ws.send(msg);
sendFile(fileDom1);
sendFile(fileDom2);
alert("Your application has been submitted.");
form.reset();
previewDom1.src = "";
previewDom2.src = "";
});
};
window.onload = start;
C# winform服务端
websocket服务端与客户端通信,通过收到数据的开头子串判断是收到了图片base64码还是文本信息。
// websocket实现与客户端通信
private void StartServer()
{
FleckLog.Level = LogLevel.Debug;
var server = new WebSocketServer("ws://0.0.0.0:7181");
server.Start(socket =>
{
socket.OnOpen = () => { };
socket.OnClose = () => { };
// 收到信息后自动添加到数据库
socket.OnMessage = message =>
{
if (!message.StartsWith("data:image/")) // 收到的消息是个人信息
{
addfromClient(message);
}
else // 收到的消息是身份证照片
{
saveidcardImage(message);
}
};
});
}
收到个人信息后的处理详见前置模块,下文介绍收到图片后的处理。
base64码开头会有一些固定的数据信息,在复原图片时这些信息不能被识别,要提取出有用的信息后将其去除。
代码中的image_directory是指定的路径,current_register_idcard是当前用户的身份证号,由于有两张图片,因此要在图片名称上用_a和_b区别开。
// 将客户端发来的身份证照片的base64码复原成图片,并存储到本地文件夹
private void saveidcardImage(string msg)
{
// base64码预处理
string hz = msg.Split(',')[0].Split(';')[0].Split('/')[1];
string[] str = msg.Split(',');
byte[] imageBytes = Convert.FromBase64String(str[1]);
//读入MemoryStream对象
MemoryStream memoryStream = new MemoryStream(imageBytes, 0, imageBytes.Length);
memoryStream.Write(imageBytes, 0, imageBytes.Length);
// 保存图片
Image image = Image.FromStream(memoryStream);
string filename = image_directory + current_register_idcard + "_a." + hz;
if (!File.Exists(filename))
{
image.Save(filename);
}
else
{
filename = image_directory + current_register_idcard + "_b." + hz;
image.Save(filename);
}
}
总结
websocket相比ajax更偏向于实时交互的信息,且安全性较高,经过测试一般的抓包工具无法从数据中提取有价值的信息;
在传输图片这里我遇到了不小的麻烦,因为C#的Fleck包本身并不支持传输文件和图片,网上也很少有用C#做这个功能的博文,转成base64码的处理方式是一个可以实现的途径;
如果需要限制上传图片大小,可以在js文件中的图片校验那里增加大小的校验。

浙公网安备 33010602011771号