细说Web页面与本地电脑通讯

话说在很久很久以前。Web页面与客户的本地电脑Localhost通讯,有两种方式:

1。Flash  
2。ActiveX控件

 

 

为什么 Adobe 公司要主动放弃这样一款已经运营了十多年,且功能也相对完善的插件呢?这与它的竞争对手——“HTML5 标准”的发展有着极大的关系。
HTML 是一种公开、通用的网页语言标准。Flash 当年能大获成功,很大程度上是因为当时的 HTML 太菜。不过随着苹果、微软等互联网公司这些年来的不断推进,HTML5 现在已经能实现和 Flash 差不多的功能了。
如今各大 App 的年终盘点页面、抢红包活动之类,几乎都是用 HTML5 技术实现的。
虽然 HTML5 似乎足以取代 Flash,但这并非是后者被淘汰的真正缘由。Flash 的死因在于自身封闭的环境,这也是它诞生时就埋下的祸根——Flash 是一款 Adobe 公司私有的版权软件。
对于苹果、微软这样的互联网巨头来说,他们并不希望如此关键的技术被掌握在其他公司的手中。
这也是为什么他们会选择推行 HTML5 这样公开的行业标准,因为 HTML 属于所有人,而非某个公司。
苹果公司早在十年以前就不待见 Flash 了,那时乔布斯专门针对 Flash 发表了一篇通告,实际读起来更像是批评。
文中表示 Flash 的漏洞多、不安全、运行效率低,还不适配触屏,有着许多弊端。
在这之后,苹果与谷歌都相继停止了 Flash 在自家手机平台上的支持,随着 HTML5 在移动化时代崛起,Flash 也逐渐显露出疲态。
Adobe 旗下还有很多产品
就这样,在 HTML5 和它背后大厂的压力之下,Adobe 选择结束对 Flash Player 的支持,并宣布将于 2020 年底正式停止它的运行。
他走后,岁月依然静好
对于 Flash 的离开,很多人没有实感——因为在主流浏览器的默认屏蔽策略之下,网页上的 Flash 插件早在几年前就开始逐渐消失,或是以 HTML5 的方式更换了,甚至我们现在看到的弹窗小广告,也几乎都是用 HTML5 制作的。
Flash 早已名存实亡,2021 年 Win10 更新后的强制抹杀,不过是在 Flash 的棺材板上又钉了几根钉而已。
但在国内,情况有些特殊。由于 Flash 在国内是被代理运营的,在官网安装的也都是“国行特供版”,更糟的是,这个国行版不仅会像流氓软件一样,弹窗各种低俗新闻和页游广告,还会正大光明地收集用户的信息。




由于Flash本人不是很了解,也给出不了什么示例代码,

对于ActiveX控件来说,可以直接在在网络上搜索“ActiveX控件”,就会有很多相关的答案

但是:

  对于现代浏览器来说,以上两种方式都通通不支持了

  对于Flash来说,虽然现在浏览器还有支持,但是都不是默认加载Flash插件了

  要用户手工点同意才会加载。

  对于ActiveX控件来说,只在IE浏览器里面才受支持,而且也要用户同意,更别说现代浏览器了

所以说。对于现代的浏览器。要与本地电脑通讯。上面两种方式已经行不通了。

 

那有没有不要用户点同意,就可以直接通过Web页面与本地电脑通讯呢?

答案是当然有了。不然也不会有此文章了。

 

对于Web与服务器通讯,我们走的是HTTP协议。这也是所有浏览器都支持的
也不会管现在浏览器和远古时代的浏览器也都支持HTTP协议。

那么

如果Web要与本地电脑通讯,只要Web与本地电脑走HTTP协议通讯。问题不就解决了吗?

那怎么实现呢?

既然要与本地电脑走HTTP协议通讯,那本地就必需要有一个支持HTTP协议的通道
平常我们与远程服务器通讯是怎么访问的,比如说百度吧,我们输入http://www.baidu.com就能正常打开了
那我们本地怎么办呢,我们做开发测试的时候,是不是输入:http://localhost 或者 http://127.0.0.1是不是就访问的我们本地电脑
那么,我们在页面里向本地发送一个请求。会有什么结果?

我们来实验一下:

首先,既然要与本地服务器通讯。那么我们在本地要监听一下本地的http协议通讯,代码如下

复制代码
namespace LocalApp
{
    class Program
    {
        public static HttpListener listener = new HttpListener();
        static void Main(string[] args)
        {
            listener.Start();
            listener.Prefixes.Add("http://127.0.0.1:8976/");//我们监听本地电脑8976端口的HTTP协议
            Thread t = new Thread(new ThreadStart(clientListener));
            t.Start();
            while (true)
            {
                string s = Console.ReadLine();
                listener.Stop();
                listener.Close();
            }
        }
        public static void clientListener()
        {
            while (true)
            {
                try
                {
                    //如果收到讲求,我们就开启一个线程去处理请求
                    HttpListenerContext request = listener.GetContext();
                    ThreadPool.QueueUserWorkItem(processRequest, request);
                }
                catch (Exception e) { Console.WriteLine(e.Message); }
            }
        }
        public static void processRequest(object listenerContext)
        {
            try
            {
                var context = (HttpListenerContext)listenerContext;
                var dicPar = new Dictionary<string, string>();
                var listPar = new List<string>();
                //拿到请求参数
                foreach (var item in context.Request.QueryString.AllKeys)
                {
                    listPar.Add(String.Format("{0}={1}", item, context.Request.QueryString[item]));
                    dicPar.Add(item, context.Request.QueryString[item]);
                }
                //设置返回值
                var resultJson = JsonConvert.SerializeObject(dicPar);
                Console.WriteLine(String.Join(Environment.NewLine, listPar));
                context.Response.StatusCode = (int)HttpStatusCode.OK;
                context.Response.ContentLength64 = System.Text.Encoding.UTF8.GetByteCount(resultJson);
                context.Response.ContentType = "application/json";
                context.Response.ContentEncoding = Encoding.UTF8;
                context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
                //返回结果
                System.IO.Stream output = context.Response.OutputStream;
                using (StreamWriter writer = new StreamWriter(output))
                {
                    writer.Write(resultJson);
                    writer.Close();
                }
            }
            catch
            {
            }
        }
    }
}
复制代码

 

上面的代码就是监听本地电脑8976端口的HTTP协议,
如果收到请求。就提取参数,然后以Json的形式返回

那么,我们写一个Html页面,向本地8976端口发送数据会出现什么情况
代码如下:

复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="Scripts/jquery-3.3.1.js"></script>
</head>
<body>
    <form id="form1" enctype="application/x-www-form-urlencoded">
        <div><label>参数1:<input type="text" name="Par1" /></label></div>
        <div><label>参数2:<input type="text" name="Par2" /></label></div>
        <div><button type="button" onclick="btnSubmit()">提交</button></div>
    </form>
    <script>
        function btnSubmit() {
            $.get("http://127.0.0.1:8976/", $("#form1").serialize(), function (result) {
                console.log(result);
            }, "json");
        }
    </script>
</body>
</html>
复制代码

 

打开Chrome浏览器做一下测试。结果如下:


页面成功的发起了请求,本地电脑APP也监听到了Web发来了请求,参数也都拿到了。
是不是我们就可以用这种方式用Web端来调用本地电脑的资源了

 

以知问题:

当我们的站点是以https访问的时候,如果用http去请求本地资源,而不是用https去请求的话,有些浏览器会报Mixed Content错误
但是在新版本的谷歌与火狐已经解决了此问题,参考:https://bugzilla.mozilla.org/show_bug.cgi?id=903966


另外一个有一个秘密,一般人我不告诉他
你们知道当你们在本地登录了QQ后,然后打开QQ的Web站点,他为什么就能自动知道你当前登录的QQ吗?

没错,他也用了这种方案与QQ通讯,从而知道你登录了哪个QQ,这样才会有此快速登录的功能

思维扩展:
这种访案只能是Web发起请求,本地电脑接受请求。只支持单一方向通讯,
那么,有没有支持双向通讯的方案呢?(Web到本地,本地到Web)
如果有知道答案的。可以在此博文下说出你的想法。

https://www.cnblogs.com/liuju150/p/Html_Web_To_Local.html

 

posted @ 2018-05-08 21:28  沧海一滴  阅读(1377)  评论(0编辑  收藏  举报