本文基于 manifest v3
插件使用 Web 技术开发
浏览器提供额外的插件 API
插件与网页分离,运行在一个独立的环境中
插件 API 功能
管理 Tabs、窗口、历史记录、书签、Cookies、下载、浏览数据、通知、网站权限
管理浏览器的外观和感觉 - 背景、主题、右键菜单、新标签页、启动页面
定制 DevTools
向网页注入脚本,与网页通信,与系统中的 Native 应用程序通信
修改/监听发送的 HTTP 请求/接收的回复
插件构成
结构 | 功能 | 调用 API | 操作 Dom | 进程 |
manifest | 配置文件 | - | ||
popup | 弹出对话框 | 所有 | Extension process | |
option page | 用户使用的设置页面 | 所有 | ||
background script | 后台脚本 | 所有 | 禁止? | Extension process |
content script | 内容脚本(注入到网页中) | 有限 | 允许 | Renderer process |
* 即便 content script 是注入到网页中的,而且是运行在 Renderer 进程(与主网页相同的进程),但是它们仍运行在不同的世界(world)。主网页运行在 main world,插件的 content script 运行在 isolated world。比如说 main world 中有一个变量,它在 isolated world 中是访问不到的,但是如果修改了 dom,对其它世界是有影响的。
将 Chrome 插件迁移到 Edge
移除 Chrome 独有的 API(如调用 Google 账户)
移动 update_URL 字段(如果是从 Chrome 商店直接下载的包会有这个字段)
改名 Chrome 相关的文字(插件名称、描述文字)
参考文献
本文使用 ASP.NET 6 版本 Senparc.Weixin.Sample.MP 示例项目改造。
第一步 注册多公众号
方法一:打开 appsettings.json 文件,在 SenparcWeixinSetting 节点内添加数组节点 Items,该对象类型同 SenparcWeixinSetting。
//Senparc.Weixin SDK 设置
"SenparcWeixinSetting": {
"IsDebug": true,
"Token": "",
"EncodingAESKey": "",
"WeixinAppId": "",
"WeixinAppSecret": "",
"Items": [
{
"IsDebug": true,
"Token": "a",
"EncodingAESKey": "a",
"WeixinAppId": "a",
"WeixinAppSecret": "a"
},
{
"IsDebug": true,
"Token": "b",
"EncodingAESKey": "b",
"WeixinAppId": "b",
"WeixinAppSecret": "b"
}
]
}
方法二:修改 Program.cs 文件,在 UseSenparcWeixin 方法中注册多个公众号信息。
var registerService = app.UseSenparcWeixin(app.Environment,
null /* 不为 null 则覆盖 appsettings 中的 SenparcSetting 配置*/,
null /* 不为 null 则覆盖 appsettings 中的 SenparcWeixinSetting 配置*/,
register => { /* CO2NET 全局配置 */ },
(register, weixinSetting) =>
{
//注册公众号信息(可以执行多次,注册多个公众号)
//register.RegisterMpAccount(weixinSetting, "【盛派网络小助手】公众号");
foreach (var mp in 从数据库或配置文件中获取的公众号列表)
{
register.RegisterMpAccount(new SenparcWeixinSetting
{
//IsDebug = true,
WeixinAppId = mp.AppId,
WeixinAppSecret = mp.AppSecret,
Token = mp.Token,
EncodingAESKey = mp.EncodingAeskey,
}, mp.Name);
}
});
完成后,我们可以从 Config.SenparcWeixinSetting.Items 获取这些信息。
第二步 接入验证与消息处理
打开 WeixinController 控制器,将构造函数改写为:
public WeixinController(IHttpContextAccessor httpContextAccessor)
{
AppId = httpContextAccessor.HttpContext!.Request.Query["appId"];
var MpSetting = Services.MPService.MpSettingByAppId(AppId);
Token = MpSetting.Token;
EncodingAESKey = MpSetting.EncodingAESKey;
}
示例中 Services.MPService.MpSettingByAppId() 方法实现从 Config.SenparcWeixinSetting.Items 返回指定 appId 的公众号信息。
为使 IHttpContextAccessor 注入生效,打开 Program.cs,在行
builder.Services.AddControllersWithViews();
下方插入
builder.Services.AddHttpContextAccessor();
这样,我们就可以在构造函数中直接获取地址栏中的 appId 参数,找到对应的公众号进行消息处理。
第三步 消息自动回复中的 AppId
打开 CustomMessageHandler.cs,将
private string appId = Config.SenparcWeixinSetting.MpSetting.WeixinAppId;
private string appSecret = Config.SenparcWeixinSetting.MpSetting.WeixinAppSecret;
替换为:
private string appId = null!;
private string appSecret = null!;
并在构造函数中插入
appId = postModel.AppId;
appSecret = Services.MPService.MpSettingByAppId(postModel.AppId).WeixinAppSecret;
这样,本页中使用的 appId / appSecret 会从 postModel 中获取,而非默认公众号。postModel 已在 WeixinController 中赋值当前的 appId。
改造后,我们可以在 OnTextRequestAsync() 等处理消息的方法中可以判断 appId 来处理不同的消息。
第四步 其它功能和接口
其它功能和接口均可用指定的 AppId 和对应的 AppSecret 进行调用。
论坛出现动态页面打开或刷新非常慢(超过半分钟),甚至打不开,该页无法显示,502 Bad Gateway 等情况,TTFB 计时需要好几秒。
切换 nginx 版本、php 版本 等均无效果,甚至购买新的 ECS 重新搭建环境也是效果甚微。
最终在阿里云 RDS 管理中,手动主备库切换,问题得以解决。
因此大概率是原主库有问题(有损坏的表需要修复或锁等情况)。
查询故障时间段的慢 SQL,发现某表的锁等待时间特别长,不知道是不是这个表的原因导致的。
次日,提交工单得到回复是原主库(现备库)会自动修复,经再次主备库切换测试得到了肯定的结果。
再次日,又遇到同样的打开慢的情况,这次直接找到慢 SQL 中锁等待时间较长的表,优化(OPTIMIZE TABLE)(虽然是 InnoDB),立刻解决了问题。
在 Discuz! 论坛中,帖子的楼层号是从主题开始计的,即“楼主”是 1#,“沙发”是 2#,“板凳”是 3#,“地板”是 4#,从 5# 开始直接以数字显示,所以我们在计算中奖楼层时,应排除主题帖所在的 1#。以活动截止时的最大楼层号 1000# 为例,允许中奖的楼层数应为 999。据此设计了以下中奖算法:
1、将****年*月*日的上证指数收盘价(含两位小数)×100
2、将得到的 6 位数字按倒序排列
3、用这个新的 6 位数除以总的回复楼层数(即活动截止时的最大楼层号-1),得到余数
4、将余数+2 即为中奖楼层
以2020年9月30日上证指数收盘价为例:3218.05×100=321805,倒序后是 508123,若截止时间前的最大楼层号为 1000,那么 508123÷(1000-1)=508 余 631,则中奖楼层号为:631+2=633。
注:
股市 15:00 收盘,但更新收盘价会延迟若干秒,因此稍候查看收盘价更为准确。
论坛发帖会有延时,特别是在抢楼这种高并发的情况下,在“抢楼主题”类型中设置了结束时间后,实际结束时的最终一个回帖的时间仍然可能超过活动截止时间(比如超过 1 秒),所以应在活动说明中明确具体以哪一个楼层结束。
其它活动说明:如不按规定回复中奖无效,不重复中奖的顺延方案,中奖楼层不存在的顺延方案等。
上证指数实时获取接口:http://hq.sinajs.cn/list=sh000001
返回结果例:var hq_str_sh000001="上证指数,开盘价,昨收价,最新价,最高价,最低价,0,0,总手,金额,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,日期,时间,00,";
特别注意,传入不同股票代码返回结果数据中的保留小数位数不同,上证指数保留了四位小数,应四舍五入保留两位小数后参与计算。
经 2020.02.22 提交工单咨询回复,阿里云控制台暂无法针对 CDN 的域名或 OSS 的 Bucket 来区分费用账单,但 ECS、RDS 可根据实例 ID 来查询:
虽然不能准确查询 CDN 各域名的消费情况,但我们可以在 CDN 的统计分析中查询域名排行,从而可以按流量占比再结合 CDN 的总体费用来计算各域名的大致费用:
当然,能把 HTTPS 等增值服务和资源包等因素考虑进去会更加合理。
与 2.X 不同的是,待审核的主题和回复是分开两张表存放的:
pre_forum_thread_moderate
pre_forum_post_moderate
字段 status 值含义:
0:未审核
1:已忽略
不在该表中的为已通过。
用过 FlashFXP 的朋友可能会它强大的功能赞不绝口,但不免费啊,用破解版对咱们的账号安全也存在一定风险。所以平常用得最多的是免费开源的 FileZilla。
今天我把觉得 FileZilla 最应该支持的“计划任务”和“站点对传”两个功能在官方论坛进行了咨询。据 FileZilla 官方回复,暂时没有支持“计划任务”的时间表,而且由于不兼容 SFTP 的原因,服务器对服务器的直接传输也无法实现。(他可能误解了我说的“站点对传”的意思了吧)
删除主题时,会变更主题表 pre_forum_thread:
displayorder = -1
moderated = 1
帖子表(或分表) pre_forum_post* 该主题的所有帖子的
invisible = -1
同时 pre_forum_threadmod 会新增一条 DEL 记录,用于显示到 Discuz! 控制面板 - 内容 - 主题回收站。
删除回帖时,会变更回帖表 pre_forum_post(或分表):
invisible = -5
屏蔽回复时,会变更回复表 pre_forum_post(或分表):
status = 1
* 仅列出部分数据表及字段
mag_ads 广告
名 | 类型 | 注释 |
id | int | |
title | varchar | 标题 |
pic | varchar | 图片 |
begin_time | int | 开始时间 |
end_time | int | 结束时间 |
link | varchar | 链接 |
…… |
mag_circle 圈子(相当于 PC 版的版块)
名 | 类型 | 注释 |
id | int | |
name | varchar | 名称 |
…… |
mag_common_applaud_(n) 点赞详情表(分表)n 与 content_id 末位一致
名 | 类型 | 注释 |
id | int | |
type | varchar | 类型(主题/回复/打卡等) |
content_id | int | 内容 id,末位与表名后缀一致 |
user_id | int | 用户 id |
status | int | 1:点赞;0:取消点赞 |
mag_common_attachment_(n) 附件详情表(分表)n 与 aid 末位一致
名 | 类型 | 注释 |
aid | int | 附件ID(末位与表名后缀一致) |
…… |
mag_common_attachment_index 附件索引表
名 | 类型 | 注释 |
id | int | 附件ID |
user_id | int | 用户ID |
table_id | int | 分表标志 |
…… |
mag_common_comment_index 评论索引表(相当于 PC 版的回复表)
名 | 类型 | 注释 |
id | int | 附件ID |
content_id | int | 文章ID(mag_show_content) |
user_id | int | 用户ID |
content | varchar | 评论内容 |
…… |
mag_common_content_log 对圈子内容的操作日志(点赞、评论等)
名 | 类型 | 注释 |
id | int | |
type | varchar | 用户ID |
type_value | int | 内容ID |
user_id | int | 用户ID |
create_time | int | 操作时间 |
…… |
mag_show_content 圈子内容(相当于 PC 版的主题表)
名 | 类型 | 注释 |
id | int | |
user_id | int | 用户ID |
content | varchar | 内容 |
pics | varchar | 以半角逗号分隔的图片(附件)id |
…… |
mag_user 用户表
名 | 类型 | 注释 |
user_id | int | 用户ID |
name | varchar | 用户名/昵称 |
head | varchar | 头像 |
…… |
公众号的报警群中经常收到这样的消息:
Appid: *
昵称: *
时间: *
内容: 微信服务器向公众号推送消息或事件后,开发者5秒内没有返回
次数: *分钟 *次
错误样例: [OpenID=*][Stamp=*][3rdUrl=http://api.socialbase.cn/extapi/wechat/message/*/][IP=*][Event=Click Menu Url]
报警排查指引,请见: http://url.cn/ab0jnP
除此之外还有另外一个问题,就是客户端发送图片后会收到两条回复,一条是“印美图”处理打印图片链接,另一条是识脸判断年龄的图文。前者是之前与印美图公司合作的与快速打印照片设备配合吸粉的功能,后者是跳转到使用 FACE++ 的页面显示图片中人物的年龄。
几天来一直找不出原因,代码中搜索错误关键词无果,被动回复消息整个流程断点逐步调试也没有发现哪里有返回“请点击这里预览印美图 点击此处裁剪相片并打印。”
不是开发模式的问题,那一定在公众平台,登录后终于在“开发”的“基本配置”页找到了“管理已授权的第三方平台”,找到“Socialbase”取消授权即可。
整个世界安静了……