基于HTTP可供浏览器调用的本地打印程序
之前给公司做打印都是用ActiveX控件,只支持IE浏览器,最近需要支持谷歌,又不想去学谷歌插件编写,于是就用本地启动一个http服务器来供浏览器调用(写成windows服务更好),同事用了都说好(笑)!为了方便大家使用,重新简单的封装了一下,源码下载:点我下载
源码简单的封装了一个webserver(基于httplistener,可以使用Nancy框架代替),可以大致了解HTTP服务器处理的流程:APACHE,NINGX等服务器主要负责响应浏览器HTTP(基于SOCKET)的请求,并将请求转交给JAVA,C#,PHP等语言处理(应该就是启动了一个该语言的虚拟机解析执行对应的代码),再将处理结果返回给浏览器
namespace LocalPrint.Web
{
//本地微型HTTP服务器,可以理解网络请求处理的服务器处理流程
class WebServer
{
HttpListener httpListener;
public string Err;
Dictionary<string, IHttpHandler> handlerMap = new Dictionary<string, IHttpHandler>();
//启动本地HTTP服务器,相当于APACHE,NGINX之类的WEB服务器,接受浏览器发送过来的SOCKET请求
public bool RunWeb(string url)
{
try
{
httpListener = new HttpListener();
httpListener.Prefixes.Add(url);
httpListener.Start();
var th = new Thread(Process);
th.IsBackground = true;
th.Start();
return true;
}
catch (Exception ex)
{
Err = "启动本地服务器出现问题:" + ex.Message;
return false;
}
}
//设置相应路由和相应的处理类
public bool AddHandler(string url,IHttpHandler httpHandler)
{
try
{
handlerMap.Add(url, httpHandler);
return true;
}
catch (Exception ex)
{
Err = "添加路径出错:" + ex.Message;
return false;
}
}
//HTTP数据处理,这一部分相当于C#,JAVA和PHP和其他语言的功能,WEB服务器将请求转发给相应的语言处理,并把结果返回给浏览器
void Process()
{
for (; ; )
{
var cnx = httpListener.GetContext();//获取浏览器请求上下文,串行处理,也可以改成并行
var req = cnx.Request;
var rep = cnx.Response;
rep.ContentEncoding = Encoding.UTF8;
rep.Headers.Add("Access-Control-Allow-Origin", "*");//允许浏览器跨域!非常重要
rep.StatusCode = ;
var ret = "pag not found";
//rep.ContentType = "text";//返回内容,这里为text,ajax里面的请求datatype也需要设置为text或者html,不然会为null
//这一部分其实就是大部分MVC网络框架里的路由部分!这里简单的发送原始文本给handler处理
foreach (var kv in handlerMap)
{
if(System.Text.RegularExpressions.Regex.IsMatch(req.RawUrl,kv.Key))//正则匹配
{
var data = "";
if (req.HttpMethod == "GET")
data = req.RawUrl;//不做任何处理,直接将原始的http请求转发到handler。。。
else
using (var r = new StreamReader(req.InputStream, Encoding.UTF8))
{
data = r.ReadToEnd();
}
ret = kv.Value.Handler(data);
rep.StatusCode = ;//ok
break;
}
}
//返回处理结果给浏览器
using (var w = new StreamWriter(rep.OutputStream, Encoding.UTF8))
{
w.WriteLine(ret);
}
}
} }
}
void Process()
{
for(; ; )
{
var cnx = httpListener.GetContext();
var req = cnx.Request;
var rep = cnx.Response;
rep.Headers.Add("Access-Control-Allow-Origin", "*");
var txt = "";
if (req.HttpMethod == "POST")
{
var fp = "";
using (var r = new StreamReader(req.InputStream, Encoding.UTF8))
{
fp = r.ReadToEnd();
}
var printer = req.QueryString["printer"];
switch (req.Url.LocalPath)
{
case "/printZPP":
printComp1.Print(fp, printer);
break;
case "/printTJBB":
printComp1.PrintBB(fp, printer);
break;
case "/printQD":
printComp1.PrintQd(fp, printer);
break;
case "/printAll":
printComp1.UniversalPrint(fp, printer);
break;
default:
//rep.StatusCode = 404;
txt = "";
break;
}
}
else
{
switch (req.Url.LocalPath)
{
case "/GetPrintNames":
txt = printComp1.GetPrinterNames();
break;
case "/GetPrinter":
{
var id = req.QueryString["id"];
txt = printComp1.GetLocalPrinter(id);
}
break;
case "/SetPrinter":
{
var id = req.QueryString["id"];
var printer = req.QueryString["printer"];
printComp1.SetLocalPrinter(id, printer);
}
break;
default:
txt = printComp1.GetPrinterNames();
//rep.StatusCode = 404;
txt = "";
break;
}
} using (var w = new StreamWriter(rep.OutputStream, Encoding.UTF8))
{
w.WriteLine(txt);
}
}
}
HTTP处理接口,PrintHandler派生此接口处理打印任务,也可以派生接口执行其他本地任务,只是简单的处理get和post文本,没有具体的参数解析,需要类自行解析。。。
//类似于MVC框架的ACTION或者CONTROLER,可派生此接口实现其他操作
public interface IHttpHandler
{
string Handler(string txt);//简单的处理文本消息
}
IPrint打印接口,派生此接口执行具体打印任务,打印格式这块可以封装出一整套的处理代码(常用的标签,表格打印和格式设置),有空再处理了
//打印接口,需要打印格式,派生此接口即可
public interface IPrint
{
bool Print(Graphics g);//返回值为是否还有打印需要打印的页内容,即是否打印结束
}
启动本地服务器后,浏览器直接访问或ajax跨域访问本地服务器即可调用本地处理服务!
$.ajax({
url : "http://localhost:23333/print",
type : "POST",
contentType: "application/json;charset=utf-8",
data : "{'name':'大萝卜卜','age':32,'sex':true}",
dataType : "text",
success : function(result) {
if (result == "ok") {
alert("打印成功!");
} else {
alert("打印出错:"+result )
}
},
error:function(msg){
aler('Error:'+msg);
}
})
本地测试
var web = new WebClient();
var txt = textBox1.Text;
byte[] bytearray = Encoding.UTF8.GetBytes(txt);
txt = Convert.ToBase64String(bytearray);
txt = System.Web.HttpUtility.UrlEncode(txt, Encoding.UTF8);//必须经过url编码
web.Encoding = Encoding.UTF8;
web.Headers.Add("ContentType", "application/x-www-form-urlencoded"); try
{
var ret = web.UploadString("http://127.0.0.1:1234", "POST", "args=" + txt);
textBox2.Text = Encoding.UTF8.GetString(Convert.FromBase64String(ret)); }
catch (WebException ex)
{
var rsp = ex.Response as HttpWebResponse;
if(rsp !=null)
{
var code = (int)rsp.StatusCode;
textBox2.Text = code + "\r\n";
var stream = rsp.GetResponseStream();
using (var s = new StreamReader(stream))
{
textBox2.Text += s.ReadToEnd();
}
}
else
{
textBox2.Text = ex.Message; }
}
为了发表博客,花了2个小时,把代码整理,简单的封装成接口,平常写代码哪有这么费事,分分钟写完交差了事(意大利面条,笑),写文章不易,点个赞吧。
基于HTTP可供浏览器调用的本地打印程序的更多相关文章
- 学习笔记:URL Protocol在浏览器中打开本地应用程序
看到阿里的网站上可以通过点击卖家的旺旺图标从而调用本地的阿里旺旺程序,而且还可以传递当前浏览者需要咨询的商品.这是怎么实现的呢?是通过URLProtocol来完成. 原理还没有太清楚,即在系统里注册一 ...
- chrome浏览器插件启动本地应用程序
chrome浏览器插件启动本地应用程序 2014-04-20 00:04:30| 分类: 浏览器插件|举报|字号 订阅 下载LOFTER我的照片书 | chrome的插件开发这里就 ...
- 一个实现浏览器网页与本地程序之间进行双向调用的轻量级、强兼容、可扩展的插件开发平台—PluginOK中间件
通过PluginOK中间件插件平台(原名本网通WebRunLocal)可实现在网页中的JavaScript脚本无障碍访问本地电脑的硬件.调用本地系统的API及相关组件,同时可彻底解决ActiveX组件 ...
- ubuntu下浏览器调用本地应用程序
ubunut下浏览器调用本地应用程序需要desktop文件和scheme协议的支持,和windows 的url protocol类似,只是注册协议的方式不一样. 首先是desktop文件,里面需要加入 ...
- mac 下基于firebreath 开发多浏览器支持的浏览器插件
mac 下基于firebreath 开发多浏览器支持的浏览器插件 首先要区分什么是浏览器扩展和浏览器插件;插件可以像本地程序一样做的更多 一. 关于 firebreath http://www.fir ...
- 可以供MFC调用的,QT实现的DLL(使用qt-solutions的qtwinmigrate实现)
MFC和QT的消息循环机制不同,所以,要让QT写的DLL可以供MFC调用,要做一点特殊的处理 #include <qmfcapp.h> #include <qwinwidget.h& ...
- 可以供MFC调用的,QT实现的DLL(qtwinmigrate实现)
MFC和QT的消息循环机制不同,所以,要让QT写的DLL可以供MFC调用,要做一点特殊的处理 #include <qmfcapp.h> #include <qwinwidget.h& ...
- asp.net core系列 58 IS4 基于浏览器的JavaScript客户端应用程序
一. 概述 本篇探讨使用"基于浏览器的JavaScript客户端应用程序".与上篇实现功能一样,只不过这篇使用JavaScript作为客户端程序,而非core mvc的后台代码Ht ...
- python selenium中如何测试360等基于chrome内核的浏览器
转自:https://blog.csdn.net/five3/article/details/50013159 直接上代码,注意是基于chrome内核的浏览器,基于ie的请替换其中的chrome方法为 ...
随机推荐
- 产品经理说|AIOps 让告警管理变得更智能
AIOps 人工智能和IT运营支撑 Ops 之间的故事,愈演愈烈,已经成为当今运维圈的热门话题,我打算从2篇文档分享我们在 AIOps 上一些探索和实践.(本篇)为什么事件(告警)处理需要 AIOps ...
- 关于linux 安装libxml2
安装php的时候提示libxml2 未安装 从服务器安装libxml2 提示 libxml.c:3821: error: expected '=', ',', ';', 'asm' or '__att ...
- EF CodeFirst使用Nuget更新数据库
常用命令: 1.开启迁移 Enable-Migrations -EnableAutomaticMigrations 2.添加一条迁移记录 Add-Migration AddMigration001 3 ...
- 用emacs 阅读 c/c++ 代码
在emacs编程中有以下需求 从调用一个函数的地方跳转到函数的定义的地方 或是反过来从函数定义的地方列出所有调用这个函数的地方 实现办法 需要安装以下软件 gnu global(阅读源代码的工具)官网 ...
- Windows10家庭版连接远程桌面出现credssp加密oracle修正问题
我发现我的win10不能连接别人的远程桌面,问题如下: 1.windows10家庭版需要修改注册表,家庭版没有组织策略: 2.win+R打开快速启动命令行输入"regedit": ...
- 怎么将后缀为.opt,.frm,.myd,.myi文件还原或者是导入mySQL中
其实这个问题的解决方案很简单,把这些文件连同这些文件所在的文件夹原封不动地复制到你的 mysql 文件夹下的 data 里面 (在我的电脑里面是D:\xampp\mysql\data), 然后你进my ...
- 解决git push时发现有超过100M的文件时,删除文件后,发现还是提交不上去的问题
我这里故意放了一个超过100M的文件 后续,git add ,git commit 然后,git push 此时会发现出现了错误.如果,我们再这里直接在文件系统中删除这个大的文件,然后再次提交,会发现 ...
- Markdown编辑器开发记录(一):开发的初衷和初期踩的坑
先说下选择Markdown编辑器的原因,我们进行平台开发,需要很多的操作手册和API文档,要在网站中展示出来就需要是HTML格式的文件,但是由于内容很多,不可能全部由技术人员进行文档的编写,如果是只有 ...
- Rancher2-----了解什么是rancher以及简单部署
个人理解:就是相当于openstack的图形化界面,或者说应用程序的图形化界面,rancher功能就是在图形化界面去管理容器,包括运行容器,创建网络,存储等:rancher有个应用商店,可以根据自己的 ...
- centos7下安装docker(13.4容器volume总结)
最近我们学习了docker 存储,首先docker存储有两种:storage driver和data volume. storage driver是由镜像层和容器层组成的,可以通过docker ins ...