• chrome打开本地链接


    同事之前给我提了一个需求,想实现在网页里点击链接地址后直接打开指定的地址(路径是内网共享的目录,file://share.xx.comxx)。


    浏览器因为有安全的限制,是无法访问 web 页面时,可以打开本地PC的目录。当你点击带有本地文件链接的超链接(file://),控制台上会报错:Not allowed to load local resource:


    最开始在网上搜索了一下,有二个插件看上去似乎可以满足需求。

    (1)Enable local file links

    (2)Local Explore – File Manager on web browser


    image

    插件启用后,类似下面这种效果(跟他们想要的效果还是有区别)。

    image


    Local Explore,自定义了协议,然后呼起本地 exe,再打开资源管理器,是期望的效果。但是它最大的问题是:如果路径有中文,就乱码,无法正常使用。


    它的原理倒是比较简单,修改超链接为 LocalExplore:file://xxxx,如果注册表添加了对该协议的监听,当浏览器访问该协议时,会触发指定的 exe 并传入相关的参数。


    我要解决乱码问题,先处理浏览器扩展插件,再就是替换 exe 的实现就可以了。

    image


    (1)替换插件,解决因插件 escape 导致的乱码问题(注:不太能理解作者为啥要用 JSON.parse 处理一下)

    对比了二个插件的实现,我准备在 Local Explore 插件的基础上进行精简。只留下必要的代码,然后通过开发者模式,加载进 chrome 的扩展程序里。

    image

    background.js 里的代码被我删光了,content.js 只进行一个操作,遍历文档所有超链接,然后修改其 href 属性。

    $(document).ready(function() {
        var optOpenFolders = "true";
        var protocolStr = "LocalExplorer:";
    
        // var clickEventHandler = function(evt) {
        //     evt.preventDefault();
    
        //     chrome.extension.sendMessage({
        //         cmd: "click",
        //         data: this.href
        //     });
        // };
    
        $("a").each(function(i, e) {
            if (e.href !== undefined && e.href !== null && e.href !== "") {
                if (!e.href.match(/^file:///)) {
                    return;
                }
    
                if (e.href.match(/^file:///)) {
                    if (window.debug) console.log(e.href);
    
                    e.href = protocolStr + e.href;
                    if (e.target) e.target = "_self";
                }
                // $(e).off("click", clickEventHandler);
                // $(e).on("click", clickEventHandler);
            }
        });
    });


    manifest.json 也做了一点修改

    {
        "update_url": "https://clients2.google.com/service/update2/crx",
        "version": "2021.7.6",
        "short_name": "Meteoric Local Explorer",
        "name": "Meteoric Local Explorer - File Manager on web browser",
        "description": "__MSG_extDescription__",
        "default_locale": "zh_CN",
        "icons": {
            "128": "icon/icon128.png",
            "32": "icon/icon32.png",
            "16": "icon/icon16.png"
        },
        "browser_action": {
            "default_icon": "icon/icon32.png",
            "default_title": "Meteoric Local Explorer"
        },
        "content_scripts": [{
            "matches": ["<all_urls>"],
            "js": ["jquery.js", "content.js"],
            "all_frames": false,
            "run_at": "document_start"
        }],
        "background": {
            "scripts": ["background.js"]
        },
        "options_page": "", // options.html
        "permissions": [
            "http://*/*",
            "https://*/*",
            "tabs"
        ],
        "manifest_version": 2
    }


    (2)替换 exe,支持打开中文链接

    这里我直接用 C# 简单写了一个 exe,实现了基本的功能。为了精简 Release 版本生成的内容,我对几处设置作了简单的调整

    (1)项目属性里面的,生成 –> 高级 –> 高级生成设置,输出 –> 调试信息,选择无,避免生成 pdb 文件;

    (2)App.config 的文件属性,修改‘生成操作’为‘嵌入的资源’,避免生成  *.exe.config 文件;


    这样生成的 Release 目录就是比较干净的了,只有一个叫 LocalExplorer.exe 的文件。替换掉安装在 C 盘里面的 exe(默认路径在:"C:Program Files (x86)LocalExplorerLocalExplorer.exe" )

    using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace FriendTimesLocalExplorer { class Program { static void Main(string[] args) { /* for (int i = 0, len = args.Length; i < len; i++) { // Get first param } */ if (args.Length < 1) { MessageBox.Show("File Path is Empty", "System Tips", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } string filePath = args[0]; // escape filePath = Uri.UnescapeDataString(filePath).Replace("/", "\"); // delete protocol filePath = filePath.Replace("localexplorer:", ""); filePath = filePath.Replace("file:", "");

    // get right file path filePath = filePath.Substring(filePath.IndexOf('\')); //Console.WriteLine(filePath); if (Directory.Exists(filePath) || File.Exists(filePath)) { Process p = new Process(); p.StartInfo.FileName = "explorer.exe"; p.StartInfo.CreateNoWindow = true; p.StartInfo.UseShellExecute = false; // hidden p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; p.EnableRaisingEvents = true; p.StartInfo.RedirectStandardError = true; if (File.Exists(filePath)) { p.StartInfo.Arguments = @"/select," + filePath; } else { p.StartInfo.Arguments = filePath; } try { p.Start(); // explorer.exe 异常结束时,会导致启动不断重启 p.WaitForExit(); if (p != null) { p.Close(); p.Dispose(); p = null; } } catch (Exception e) { MessageBox.Show(e.ToString(), "System error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } else { MessageBox.Show("Not Found Path : " + filePath, "System error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } }


    浏览器插件 和 exe 都进行替换后,就能实现点击链接调用本地exe,再通过 exe 打开指定的目录了。迅雷、QQ或其它客户端软件,基本上也是使用类似的原理,实现点击网页链接呼起本地的客户端应用程序(应用程序想干嘛就自己实现)


    注意点击时,会弹出一个提示。

    image

  • 相关阅读:
    java数据库连接池
    ThreadLocal遇到线程池时, 各线程间的数据会互相干扰, 串来串去
    当ThreadLocal碰上线程池
    threadLocal遇上线程池导致局部变量变化
    java自带线程池和队列详细讲解
    Java 多线程下的单例模式
    一个错误使用单例模式的场景及ThreadLocal简析
    总结SQL Server窗口函数的简单使用
    sqlserver中drop、truncate和delete语句的用法
    JBOSS连接池默认连接数是多少?在哪个配置文件有这个默认的连接数?
  • 原文地址:https://www.cnblogs.com/meteoric_cry/p/14978891.html
Copyright © 2020-2023  润新知