上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖

[油猴脚本开发指南]实现前端全自动唤醒本地后端

[复制链接]
  • TA的每日心情
    慵懒
    22 小时前
  • 签到天数: 603 天

    [LV.9]以坛为家II

    30

    主题

    523

    回帖

    1379

    积分

    荣誉开发者

    积分
    1379

    荣誉开发者新人进步奖油中2周年生态建设者新人报道挑战者 lv2油中3周年喜迎中秋

    发表于 2023-5-17 14:38:34 | 显示全部楼层 | 阅读模式

    本帖最后由 steven026 于 2023-5-17 21:17 编辑

    本帖最后由 steven026 于 2023-5-17 15:03 编辑

    前言

    本编指南内容较少、原理简单,更偏向于实现方案,主要作为理论实战篇打下基础(实战篇以后有空的时候会写)

    写这篇指南原因主要是前端限制太大,无法满足所有日常(办公)自动化需求,部分需求(比如读写文件)需要通过后端来实现,但后端在部分方面(比如网页处理)灵活性不如前端,因此可以前后端相结合,各取其长,分工合作提升自动化效率。

    本编指南
    难易度:低(新手也可看懂)
    实用性:中(省去手动运行本地后端时间)
    广泛性:低(需要有本地后端程序且需要额外注册注册表)
    (仅在windows中测试成功,其余环境未测试)

    原理

    windows支持通过注册表regedit.exe注册类似https://的本地自定义协议,可自定义设置command内容以实现通过自定义协议调用本地程序的方案。
    而这个自定义协议亦可通过浏览器前端调用,限制较少,
    因此前端使用自定义协议可以单向全自动唤醒本地后端并传输数据。
    (双向需要通过XHR等方式,本文暂不讨论,可以等待日后的实战篇)
    根据这一原理,使得油猴亦可调用本地后端,实现前后端相结合。

    初级内容

    准备工作

    本地自定义协议实际上使用非常广泛,非常多的软件都在使用,因此我们可以直接根据原理逆向其他软件的实现方案。


    1.png

    image.png

    首先要在浏览器中允许页面打开新窗口,否则会被浏览器阻止

    以GitHub为例,在安装了GitHub Desktop后,可以通过一键打开x-github-client://协议,使浏览器将目标GiuHub仓库链接传递给本地的应用程序,减少用户操作,提升用户使用体验。

    从控制台可以看到这是通过<a>标签打开的x-github-client://协议,
    这就说明我们亦可通过window.open(url)打开这一协议链接。


    image.png
    在控制台尝试一下,
    果然成功了,这就说明我们也可以在油猴脚本中使用这一特性。


    那么问题就来了,这个协议怎么注册呢?查阅相关资料可以发现,这个自定义协议是通过注册表注册的。
    因此打开regedit.exe注册表,搜索x-github-client
    image.png
    可以找到是这条注册表控制的协议注册
    image.png
    直接右键导出,可以获取如下数据,内容非常简单

    Windows Registry Editor Version 5.00
    
    [HKEY_CLASSES_ROOT\x-github-client]
    "URL Protocol"=""
    @="URL:x-github-client"
    
    [HKEY_CLASSES_ROOT\x-github-client\shell]
    
    [HKEY_CLASSES_ROOT\x-github-client\shell\open]
    
    [HKEY_CLASSES_ROOT\x-github-client\shell\open\command]
    @="\"C:\\Users\\XXX\\AppData\\Local\\GitHubDesktop\\app-3.2.3\\GitHubDesktop.exe\" \"--protocol-launcher\" \"%1\""
    

    可以看到这个注册表路径就是自定义协议名称x-github-client,而关键命令是最后一行的command,这个命令和cmd命令非常相似,
    参考这个注册表就能注册自己的协议了。

    注册表 test.reg

    Windows Registry Editor Version 5.00
    
    [HKEY_CLASSES_ROOT\test]
    "URL Protocol"=""
    @="URL:test"
    
    [HKEY_CLASSES_ROOT\test\shell]
    
    [HKEY_CLASSES_ROOT\test\shell\open]
    
    [HKEY_CLASSES_ROOT\test\shell\open\command]
    @="\"C:\\Program Files\\nodejs\\node.exe\" \"D:\\test\\test.js\" \"%1\""
    

    我们依样画葫芦,注册一个test://协议,利用nodejs调用test.js
    x-github-client全部替换为test
    将最后一行command替换为我们自己需要调用的后端调用命令
    记得将"\转义

    • \"C:\\Program Files\\nodejs\\node.exe\"是自定义程序绝对路径
    • \"D:\\test\\test.js\"是自定义参数
    • \"%1\"是打开的协议链接,这个最后不要改动,如果不需要传递数据的话可以删除

    保存后双击.reg文件进行注册表注册。

    至此我们完成了自定义协议注册工作,自定义协议无法通过前端完成,只能通过后端或者手动运行.reg文件进行注册。


    image.png
    我们在控制台中测试一下立马跳出了确认框,直接点击打开就行。
    (注:仅在https://页面中,打开协议链接会弹出始终允许选项,如果勾选了始终允许后,后续在该站点打开该协议就不会再弹出二次确认了,会直接自动打开该协议
    而在http://页面中没有始终允许的选项,每次打开协议都会弹出确认框阻塞页面,必须每次手动确认。这是浏览器特性,克服方法几乎没有,强行克服可以参考下文进阶内容)
    image.png
    可以看到我们的test.js被成功打开了,而这个协议链接也成功被之前注册表command中的%1传递了过去,我们可以利用这个特性将前端数据自动传递给后端。
    油猴脚本调用这个协议和控制台方法一样,只要在合适的时机运行原生函数即可window.open("test://XXXXX")

    进阶内容

    监听窗口事件

    testWindow = window.open('test://a')
    if (testWindow) {
        console.log("窗口打开成功")
        testWindow.onunload = () => console.log("窗口被关闭")
    } else {
        console.log("窗口打开失败,可能被浏览器阻止")
    }

    https://developer.mozilla.org/zh-CN/docs/Web/API/Window/open
    具体API使用方法不再赘述,如有需要直接查阅MDN文档即可。

    由于自定义协议不需要用到特殊API,因此可以不使用脚本管理器的GM_openInTabAPI,直接用原生的window.open即可。
    由于没有违反同源策略,因此可以监听新窗口的onunload事件。
    (似乎无法监听用户是点击了确认还是取消,只能通过其他方法实现)
    (如果勾选了始终允许onunload事件发生即代表后端成功被调用)

    在http页面中始终允许打开协议链接

    image.png
    目前发现只有在https://或者chrome-extension://使用window.open打开自定义协议链接才会有始终允许的选项框.


    image.png
    除此以外,连插件APIchrome.tabs.create都不会弹出始终允许的选项框
    (GM_openInTab也不会弹出因为其实现原理也是用了chrome.tabs.create)
    据查阅文档说是出于安全考虑,禁用了http页面的始终允许选项。
    但这也使得每次在http页面打开协议链接都会阻塞页面必须手动确认才行,非常影响自动化效率,实在不能忍!


    因此经过漫长时间的研究,发现我们只要在脚本管理器的background页面运行window.open即可绕过浏览器的http页面限制。
    那么怎么在脚本管理器的background页面运行代码呢?
    改源码即可【……
    由于油猴闭源,而脚本猫开源,因此我们直接爆改GM_openInTabAPI,然后把新代码去GitHub提交给脚本猫不就行了吗🙄。
    详细源码可以查阅GitHub
    https://github.com/scriptscat/scriptcat/pull/178
    使用了window.openchrome.tabs相结合的方式,
    实现在http页面运行油猴脚本猫脚本亦可始终允许自动打开自定义协议链接
    补上了最后一块拼图。


    该方法仅适用于脚本猫,这是一个实验性/不兼容其他管理器/不兼容Firefox的功能
    (火狐我用的实在太少,尝试了一下似乎background页面强制阻止使用window.open,无法通过这一原理实现,也有可能是我方法不对,如果有实现的大佬欢迎讨论或者提交PR)

    使用方法非常简单
    调用GM_openInTab函数,在参数中加上{ useOpen: true }即可
    该方法做了向下兼容性处理,只有在新版(v0.12.0后的版本)脚本猫中使用了{ useOpen: true }才会生效使用新方法去打开链接,并会忽略其余所有参数(因为该方法不适用默认参数)
    如果在油猴或者旧版脚本猫中即使加了该参数亦不会生效,不会造成其余不利的影响,只是会和旧GM_openInTab一样弹出没有始终允许的选项框而已

    const protocol = GM_openInTab('test://', { useOpen: true })
    protocol.onclose = () => console.log("onclose")

    完结撒花

    具体脚本前后端相结合的自动化实战篇待有空时会写,【最好不要抱太大期望

    实在写不动了……原本以为一个小时最多了,结果写了快2个小时,直接过载,灵思枯竭了,感觉还有点东西想写没写出来,一下子竟然想不起是啥了……等想起来再更新吧

    已有3人评分好评 油猫币 理由
    脚本体验师001 + 1 + 5 ggnb!
    朱焱伟 + 1 + 7 ggnb!
    tfsn20 + 1 + 5 ggnb!

    查看全部评分 总评分:好评 +3  油猫币 +17 

  • TA的每日心情
    开心
    2024-3-3 00:00
  • 签到天数: 117 天

    [LV.6]常住居民II

    27

    主题

    588

    回帖

    521

    积分

    专家

    积分
    521

    油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2023-5-17 22:04:29 | 显示全部楼层
    高,实在是高,简直有八九十层楼那么高
    入驻爱发电 让这世界充满爱 https://afdian.net/a/vpannice
    回复

    使用道具 举报

  • TA的每日心情

    2023-11-8 15:41
  • 签到天数: 17 天

    [LV.4]偶尔看看III

    3

    主题

    60

    回帖

    52

    积分

    初级工程师

    积分
    52
    发表于 2023-5-19 17:09:39 | 显示全部楼层
    就是走自定义协议,要么就是走CHrome内核的通讯接口,不管哪个都要写注册表
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表