如何检测域名在微信是否被封

通过微信的桥接地址:http://mp.weixinbridge.com/mp/wapredirect?url= , 连上自己的域名,可以通过请求该连接返回的内容,获取是否被封。

如下是 PHP 的示例代码

1
2
3
4
5
6
7
$str = file_get_contents('http://mp.weixinbridge.com/mp/wapredirect?url=http://www.baidu.com');
if (mb_strpos($result, '已停止访问该网页') !== false) {
echo '已封';
}
if (mb_strpos($result, '申请恢复访问') !== false) {
echo '已封';
}

逻辑很简单,可以根据实际情况做重试或代理。只是如果常用的功能,查阅中文互联网竟然没有明显的实现方式,疑惑。

APIFOX 设置前置脚本

日常工作中主要用 APIFOX 测试 API 接口,API 接口有很多需要鉴权的地方,如果每次都需要手动设置鉴权参数比较麻烦,可以利用官方提供的前置脚本功能设置鉴权的参数。前置脚本可以方便的使用 JS 语言编写。

官方文档:https://apifox.com/help/pre-post-processors-and-scripts/scripts/api-references/javascript-library

下面是一个示例,生成鉴权参数并设置请求头和请求参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
let secret = '鉴权密钥';

// 存放所有需要用来签名的参数
let param = {};

// 加入 query 参数
let queryParams = pm.request.url.query
queryParams.each((item) => {
if (!item.disabled && item.value !== '') {
// 启用且非空参数值的参数才参与签名
param[item.key] = item.value
}
})

// 加入 body 参数
if (pm.request.body) {
let formData;
switch (pm.request.body.mode) {
case 'formdata':
formData = pm.request.body.formdata;
break;
case 'urlencoded':
formData = pm.request.body.urlencoded;
break;
case 'raw':
// 如果没有 JSON 格式的请求 body,或 JSON 格式 body 不参与签名,可以删除这一段
let contentType = pm.request.headers.get('content-type');
if (
contentType
&& pm.request.body.raw
&& contentType.toLowerCase().indexOf('application/json') !== -1
) {
try {
let jsonData = JSON.parse(pm.request.body.raw);
/*
* 注意:通过脚本取出来的接口参数,如果参数包含变量,变量是不会替换成对应的值。如想要获取替换后的值,可使用`pm.variables.replaceIn`方法处理:
* let body = pm.variables.replaceIn(pm.request.body.raw);
* let jsonData = JSON.parse(body);
*/
for (let key in jsonData) {
let value = `${jsonData[key]}`; // 此处要注意如果值的实际类型不是 string 需要根据实际情况处理。
if (value !== '') { // 非空参数值的参数才参与签名
param[key] = value;
}
}
} catch (e) {
console.log('请求 body 不是 JSON 格式')
}
}
break;
default:
break;
}
if (formData) {
formData.each(item => {
if (!item.disabled && item.value !== '') { // 启用且非空参数值的参数才参与签名
param[item.key] = item.value;
}
});
}
}
// 添加鉴权接口需要的两个参数(个人项目需要)
param['_t'] = Math.floor(Date.now()/1000);
param['_s'] = 'ssss';
// 取 key
let keys = [];
for (let key in param) {
keys.push(key);
}

// 参数名 ASCII 码从小到大排序(字典序)
keys.sort();

// 转成键值对
let paramPair = [];
for (let i = 0, len = keys.length; i < len; i++) {
let k = keys[i];
paramPair.push(k + '=' + param[k])
}

// 拼接
let stringSignTemp = paramPair.join('&');
console.log(stringSignTemp);

let sign1 = CryptoJS.MD5(stringSignTemp).toString();
console.log(sign1);

let sign = CryptoJS.MD5(secret + sign1).toString();
console.log(sign);

// 设置请求头
pm.request.headers.add({ key: 'api-security', value: sign+""})
// 设置请求参数
queryParams.upsert({
key: '_t',
value: param['_t'] + ""
})
queryParams.upsert({
key: '_s',
value: param['_s']
})

可以在这里看到 console.log 打印的日志

在这里配置一个统一的前置脚本,方便子目录继承

homestead ssh 连接失败问题

启动 vagrant 一直报这个错误,说明是连接 ssh 使用的秘钥有问题,可能跟昨天我把虚拟机里的 authorized_keys 删了有关系。

1
2
3
4
5
6
7
default: SSH auth method: private key
default: Error: Connection timeout. Retrying...
default: Error: Connection timeout. Retrying...
default: Error: Connection timeout. Retrying...
default: Error: Connection timeout. Retrying...
default: Error: Authentication failure. Retrying...
default: Error: Authentication failure. Retrying...

这种情况需要重新配置 ssh 秘钥,我按照如下步骤解决了问题。

  1. 执行 vagrant ssh-config 查看当前虚拟机的 ssh 配置信息,输出如下

  1. 执行 ssh-keygen -m PEM -t rsa -b 4096 生成 rsa 秘钥,现在默认名称生成的秘钥是以 BEGIN OPENSSH PRIVATE KEY 开头的,与虚拟机上的类型不一致,所以生成时需要带上后面的这些参数
  2. 将生成的私钥复制到第一步的 IdentityFile 标识的私钥文件中,同时也复制到 ~/.vagrant.d/insecure_private_key 文件一份中(不复制也可以,执行 vagrant up 会自动生成)
  3. 复制刚生成本机的公钥,使用用户名密码登录到虚拟机,将公钥添加到虚拟的 authorized_keys 文件中。homestead 虚拟机的用户名和密码都是 vagrant
  4. 最后执行 vagrant reload --provision 重新配置虚拟机即可

直接执行这个命令应该就能解决这个问题:vagrant ssh -c "echo 'your_public_key' >> ~/.ssh/authorized_keys" ,将本机公钥写入到 homestead。

设置请求头跨域问题

在后端已经设置了 CORS 的 Access-Control-Allow-Origin 请求头后,如果 AJAX 请求时设置了自定义请求头,依然会报跨域的问题。报错的信息大概是 Access to XMLHttpRequest at 'http://xuanshang.test/login/dev' from origin 'http://practice.test' has been blocked by CORS policy: Request header field dev-token is not allowed by Access-Control-Allow-Headers in preflight response 。这是因为如果要设置自定义请求头,后端还需要根据是否是 OPTIONS 请求方法,设置允许的请求头。这个 OPTIONS 请求称为 预检请求 ,是浏览器在必要的时候,自动发出的。以获取被允许的请求头、请求方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header('Access-Control-Allow-Origin: ' . $allowOrigin);
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Credentials: true');
// 返回允许设置的请求头
header('Access-Control-Allow-Headers: DEV-TOKEN');
header('Access-Control-Max-Age: 86400');
header('Content-Type: text/plain charset=UTF-8');
header('Content-Length: 0');
header('status: 204');
header('HTTP/1.0 204 No Content');
exit;
} else {
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Origin: ' . $allowOrigin);
}

PHP 使用 Memcache 存储 SESSION 时, SESSIONID 的前缀

https://www.php.net/manual/zh/memcached.sessions.php

memcached 提供了一个自定义的 session 处理程序可以被用于存储用户 session 数据到 memcached 服务端。 一个完全独立的 memcached 实例将会在内部使用,因此如果需要您可以设置一个不同的服务器池。session 的 key 被存储在前缀 memc.sess.key. 之下,因此, 如果你对 session 和通常的缓存使用了 同样的服务器池,请注意这一点。 译注:另外一个 session 和通常缓存分离的原因是当通常的缓存占满了 memcached 服务端后,可能会导致你的 session 被 从缓存中踢除,导致用户莫名的掉线。

2022年终总结

2022 年即将结束,在七麦也已度过一年的时间。这一年对自己的影响还是挺大的,第一次接触盈利的互联网产品,让自己有了一些产品创造、企业生存的感触。同事多是全能型选手,公司没有专门的运维,唯一的安卓还是技术总监自学着做的。不过像七麦这样的互联网公司,确实要求技术人员应该是全能的,最起码领导层得是全能的,因为有些工作(比如运维)专门招一个人来做,人力成本太大,且该工作也不是经常有的,招完人后可能造成忙一天闲三天的情况。

回望一年的工作,让自己感觉到有提升的地方,有如下几个:

  • 做了原路退款,有了跟钱打交道的经验
  • 做了悬赏的快手的推广,有了推广对接的经验
  • 接入了穿山甲广告,有了项目广告创利的经验
  • 做了公众号绑定授权,有了微信开发的一些经验

诚然,这些经验还很浅薄,只是做了对应功能的一部分工作,但是这些都是我之前没有做过的。有了初次的经验,下一次再接触类似的需求,大脑便不会再抵触。

当然这一年还做了许多其它的工作,不过那些工作多是使用已有的经验进行需求的实现。对于这部分的工作,如果想要做的更好,应该看一些关于写代码的修养、项目工作与上线、项目安全防范的书。这些能力应该是属于程序员的软实力,一时间看不出来,却融于一点一滴的工作当中。

以往对新一年的预期多流于物质方面,这其实不太可取,因为即使实现了,也并没有什么成就感。随着一年年的过去,以前有过的考研、软考的想法都已被自己抛入脑后,日子一天天混着过。以后对新年的规划要着重于自身能力的提升,无论是哪个方面,只要是以前自己不具备的,又对自己身心有益的,都可以。不过切忌贪多,一年中干不成多少事,定个两三件即可。

这一年生活上没有什么值得称道的事,因为疫情,休息的时候也没有去其它的地方转转。10 月份的时候去了德州,婚事定于明年 10 月份。婚事一完,爸妈也算是了却了一桩心思,应该能更轻松一点。如今疫情放开,明年的话倒可以利用假期多出去走走。

明年的话,给自己定两件任务。一件是把 Go 语言学一下,对于它的 Web 开发和微服务都要了解一下,自己实际的做点东西,提升一下自己职业上的竞争力。要把 Go 官网上面的教程都看个三五遍,就看英文原版,这也是一件自己以前没做过的事。另一件是把 E 大的推荐书单都看一下,期望可以建立起自己的投资系统,有朝一日投资的收入覆盖起生活的支出。

4.4 颐和园

4.4颐和园.jpeg

10.22 环球

10.22环球.jpeg

生产环境为大表更改字段或索引的方式

生成环境的 a 表有一条慢 sql,需要为其建立一个索引。由于其表有一亿多条数据,索引不能直接在生产环境创建,所以想到的方案是创建一个跟 a 表结构相同的 b 表,并在 b 表上创建需要的索引,然后将 a 表的数据批量插入到 b 表。前段时间由于一些表不再满足业务需求,需要把主键的类型由 int 改为 bigint,同事写了一个在线上切换大表的脚本,我仿照着写了一个简单的更改一个表的。考虑到以后还可能遇到这种场景,所以把脚本记录于此。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 同步表数据
public function syncTable()
{
ini_set('memory_limit', -1);
$deadline = time() + 55;

/** @var Model $model */
$model = M('');
$sql = "SELECT max(id) FROM b";// 获取已经同步的条数
$synced_id = $model->getField($sql) ?: 0;

$limit = 100000;// 每个插入的条数
$start = $synced_id;
while (time() < $deadline) {
$sql = "SELECT id FROM a WHERE id > {$start} LIMIT 1";
if (empty($model->getField($sql))) {
sleep(3);
continue;
}

$step = $start + $limit;
$sql = "INSERT INTO b SELECT * FROM a WHERE id > {$start} AND id <= {$step}";
$model->query($sql);
$start = $step;

usleep(500);
}
}

// 重命名表
public function renameTable()
{
$deadline = time() + 55;

/** @var Model $model */
$model = M('');

while (time() < $deadline) {
$sql = "SELECT max(id) FROM a";
$max_id_1 = $model->getField($sql);

$sql = "SELECT max(id) FROM b";
$max_id_2 = $model->getField($sql);

if ($max_id_1 != $max_id_2) {
print_ln('数据未同步完');
usleep(100);
continue;
}

$sql = "RENAME TABLE a TO a_back, b to a";
$model->query($sql);

print_ln('重命名成功');

break;
}
}

ngrok的使用

ngrok 是一个实现内网穿透的工具。工作中可能需要临时性的让外部访问自己的一些功能,使用此工具可以很方便的将自己本地的虚拟主机映射到一个外网域名。

安装略。

安装好之后执行如下操作:

1
2
3
4
# 添加 authtoken
ngrok authtoken ngrok上自己的token
# 设置需要外部访问的域名,-host-header 表示本地域名,-region 后跟使用的节点,80 代表映射到主机的端口
ngrok http -host-header=practice.test -region us 80

然后 ngrok 会展示一个前台窗口,窗口中有分配的外部域名。