菜鸟谷歌浏览器打印组件技术分析
之前一直在研究浏览器调用本地程序,但发现似乎只有IE的OCX才能做到,谷歌浏览器虽然说有插件,但实现IE下OCX的功能却不太可能,忽然有一天,有个同事让我看一下菜鸟的打印组件,豁然开朗。
菜鸟的打印组件竟然是在谷歌浏览器下实现了类似IE下的OCX技术,直接可以调用打印机,但分析发现,浏览器扩展根本没有安装新东西,说明菜鸟的打印组件根本不是通过谷歌浏览器的插件机制实现的。
无奈只能分析打印按钮的HMTL代码
没有行内脚本,猜测应该是根据类选择器printBtn J_printBtn 处理的点击事件,于是保存了一份网页,在下载中的中脚本中查看可能的点击事件,竟然在newWaybillPrint.js文件中找到了可能的代码
$("body").undelegate(".J_printBtn", "click").delegate(".J_printBtn", "click", function (e) {if (!J.printBtnFlag)return !1;var t = $(e.currentTarget),a = t.attr("data-id");"undefined" != typeof socket ? J.socketReadyState = socket.readyState : x._doConnect(),0 == J.socketReadyState ? (J.printBtnFlag = !0, m.Alert("webSocket\u8fde\u63a5\u6b63\u5728\u5efa\u7acb", "info")) : 2 == J.socketReadyState ? (J.printBtnFlag = !0, m.Alert("webSocket\u8fde\u63a5\u6b63\u5728\u8fdb\u884c\u5173\u95ed", "info")) : 3 == J.socketReadyState ? (J.printBtnFlag = !0, null == J.notInitOrOpenDialog && x._renderNotInitPrintDialog(), J.notInitOrOpenDialog.show()) : (J.printBtnFlag = !1, x._printViewDialog("single"), J.previewDialog.root.attr("data-curId", a), J.previewDialog.show())}),
在浏览器中调试,明显是压缩过的代码,但点击红色部分,可以格式化,并添加断点,调试,果然是。
发现有一个 "undefined" != typeof socket ? J.socketReadyState = socket.readyState : x._doConnect(),
然后在分析socket,找到了
_doConnect: function () {var e = window.location,t = "",a = "";if ("https:" === e.protocol ? (t = "wss:", a = "13529") : (t = "ws:", a = "13528"), window.WebSocket)window.socket = new WebSocket(t + "//localhost:" + a), socket.onopen = function (e) {J.socketReadyState = e.target.readyState,x._doGetPrinters("123")},
竟然是通过WebSocket和本地的打印程序通讯,然后就可以调用本地资源了。感觉真的是太巧妙了。把打印程序作为WebSocket的服务端,这样就实现了通过浏览器调用本地资源的功能,实现了B/S,C/S巧妙结合的使用,充分合理利用了B/S,C/S的好处。
客户端浏览器和打印程序之间通过WebSocket进行交互
浏览器和菜鸟服务器是正常的BS程序
打印程序和和菜鸟服务器是正常的CS程序
简单的网页通讯代码
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <style type="text/css">body *
{
font-family:微软雅黑;font-size:14px
}</style> <script type="text/javascript">var websocket = null;//判断当前浏览器是否支持WebSocketif ('WebSocket' in window) {websocket = new WebSocket("ws://localhost:8181");}else {alert('当前浏览器 Not support websocket')}//连接发生错误的回调方法websocket.onerror = function () {setMessageInnerHTML("WebSocket连接发生错误");};//连接成功建立的回调方法websocket.onopen = function () {// setMessageInnerHTML("WebSocket连接成功");websocket.send("WebSocket连接成功");}//接收到消息的回调方法websocket.onmessage = function (event) {setMessageInnerHTML(event.data);}//连接关闭的回调方法websocket.onclose = function () {setMessageInnerHTML("WebSocket连接关闭");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function () {closeWebSocket();}//将消息显示在网页上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML +="收到消息:"+ innerHTML + '<br/>';}function closeWebSocket() {websocket.close();}function clear(){document.getElementById('message').innerHTML="";}//发送消息function send() {var message = document.getElementById('text').value;websocket.send(message);}
</script>
</head><body style="padding:0px;width:1015px"><button onclick="closeWebSocket()">关闭WebSocket连接</button><button onclick="clear()">清空</button><hr /><input type="text" id="text" /><button onclick="send()">发送消息</button><div id="message"></div>
</body>
</html>
使用Csharp插件Fleck编写的简单的模拟打印程序
using Fleck;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;namespace WindowsFormsWebSocket
{public partial class Form1 : Form{WebSocketServer server = null;// IWebSocketConnection client = null;Dictionary<Guid, IWebSocketConnection> dic = new Dictionary<Guid, IWebSocketConnection>();public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){server = new WebSocketServer("ws://127.0.0.1:8181");server.RestartAfterListenError = true;server.Start(socket =>{socket.OnOpen = () => OnOpen(socket);socket.OnClose = () => OnClose(socket);socket.OnMessage = m => OnMessage(socket, m);});}private void OnMessage(IWebSocketConnection socket, string m){MessageBox.Show("收到客户端消息:"+m);// throw new NotImplementedException();}private void OnClose(IWebSocketConnection socket){Guid id = socket.ConnectionInfo.Id;if(dic.ContainsKey(id)){IWebSocketConnection sond= dic[id];sond.Close();dic.Remove(id);} MessageBox.Show("OnClose");}private void OnOpen(IWebSocketConnection socket){Guid id = socket.ConnectionInfo.Id;if (dic.ContainsKey(id)){IWebSocketConnection sond = dic[id];sond.Close();dic.Remove(id);}else{dic[id] = socket;} }private void button1_Click(object sender, EventArgs e){ string text= textBox1.Text;foreach(var i in dic){IWebSocketConnection sond = i.Value;sond.Send(text);} }}
}
.NET 的 WebSocket 开发包比较(转)
C# 实现WebSocket服务端实例
Writing a WebSocket server in C#
The simple WebSocket application in ASP.NET
在IIS上搭建WebSocket服务器
C# Websocket Implementation
史上最全Web端即时通讯技术原理详解
WebSocket
HTML5 WebSocket
关于websocket兼容IE版本
菜鸟谷歌浏览器打印组件技术分析相关推荐
- CAD组件技术分析——概述
在计算机辅助设计领域,Autodesk有着举足轻重的作用,拥有较大的影响力.因此,基于Autodesk的产品输出的图纸(dwg)或模型(rvt)有很多的读写需求:相应地,各自组件技术也都支持这些专有格 ...
- WEB 打印的相关技术分析
文/谢康 做Web开发的人员一定都会面临一个共同的难题,那就是打印.的确,相对于Windows桌面应用程序来讲,Web应用程序的打印有种种限制,技术人员在项目开发过程中经常会遇到用户这样或那样的需求. ...
- 【华为云技术分享】一行代码就能写一个日志打印组件,你信吗?为你揭晓LiteOS中日志打印组件的核心
1. 做实验引发的思考 在学习LiteOS日志打印组件使用的时候,我记录了一篇博客:atiny_log | LiteOS 物联网操作系统中的日志打印组件使用分享,关于实验的具体内容,请阅读这篇博客. ...
- 中国人工智能学会通讯——机器人组件技术在智能制造系统中的应用
摘要:随着工业4.0时代的到来,如何将传统工厂改造成为个性化.网络化.柔性生产的智能制造系统成为了当前的研究热点.本文从智能制造系统和智能机器人系统的相似性出发,构建了基于机器人组件技术的智能制造系统 ...
- 《纯技术分析阿里云OS和Android之间的关系》补充
前面一份投稿的错误很抱歉,rom本身就找错了,用了一个AOSP-like的刷机包.好在这份内容错误的投稿多少起到了抛砖引玉的作用,当天晚上,就给出了正确的rom的分析<纯技术分析阿里云OS和An ...
- 什么是OpenMAX技术分析OpenMAX
什么是OpenMAX技术分析OpenMAX OpenMAX是统一的抽象层,它允许访问否则需要供应商特定API的硬件. Broadcom的MMAL(多媒体抽象层API). 因此,OpenMAX允许使用此 ...
- 菜鸟实时数仓技术架构演进
分享嘉宾:贾元乔 菜鸟 高级数据技术专家 内容来源:Flink Forward ASIA 出品平台:DataFunTalk 导读:在开源盛世的今天,实时数仓的建设已经有了较为成熟的方案,技术选型上也都 ...
- java超线程_超线程多核心下Java多线程编程技术分析
在学习编程的过程中,我觉得不止要获得课本的知识,更多的是通过学习技术知识提高解决问题的能力,这样我们才能走在最前方,本文主要讲述超线程多核心下Java多线程编程技术分析,更多Java专业知识,广州疯狂 ...
- Microsoft .NET Pet Shop 4 架构与技术分析(转)
Microsoft .NET Pet Shop 4 架构与技术分析 1.项目概述与架构分析微软刚推出了基于ASP.NET 2.0下的Pet Shop 4, 该版本有了一个全新的用户界面.是研究ASP. ...
- 【引用】内网安全数据保密技术分析与比较
内网安全数据保密技术分析与比较 邹翔① 王志海②,李志涛② (①公安部第三研究所上海 200031: ②北京明朝万达科技有限公司,北京 100000) [摘要]本文通过对目前主要的内网安全数据保密关键 ...
最新文章
- 辗转相除法是求两个数的最大公约数的方法。
- Microsoft SQL Server学习(二)--数据库的语法
- 网络安全逐渐成为程序员的必备技能
- 02.改善深层神经网络:超参数调试、正则化以及优化 W3. 超参数调试、Batch Norm和程序框架(作业:TensorFlow教程+数字手势预测)
- 医生们团结一致,以增加对优质健康信息的访问
- Vista忘记密码如何登录?
- java swing container_Java Swing GUI学习(一)
- 编程题:字符串的指针引用。用指针法实现。功能:将字符串str2复制连接到str1...
- 关于Cocos2d-x的动作和动画
- 泛微oa系统什么框架_泛微OA ecology 二次开发实例 开发完整说明
- 基于Java GUI的资产管理系统的设计与实现
- matlab三次方程求根,如何用matlab求一元三次方程的最小正根?
- 酒店客房管理系统总结
- S3-s3cmd命令行工具使用
- 如何解决Worm.Win32.AutoRun.bqn(文件夹改exe病毒)
- 实时网速怎么看快慢_怎么测试下载速度(教你安全检测网速快慢)
- 【一文速通】机器学习样本不均衡/数据分布不同怎么办?
- Combo( 自定义下拉框) 组件
- 【一 DE1-SOC】quartus II下载程序步骤
- 算法 所有奇数长度子数组的和
热门文章
- 正则Regex中圆括号()方括号[]大括号{}的区别和用法
- chrome extensions快捷键shortcuts配置
- testcookie-nginx-module
- 海量数据实时计算系统在高并发互联网应用中的原理和实践
- Memory ordering in some architectures
- java中文api在线测试_万邑通开发者网站 - API在线测试
- java水电费收费系统_基于jsp的电费管理系统-JavaEE实现电费管理系统 - java项目源码...
- C/C++——C++中new与malloc的10点区别
- 支持全文搜索的桌面搜索工具
- GoC全教程(附各种下载、教程链接)