持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第21天,点击查看活动详情
前言
Q: 实现微信落地页防封拢共分几步?
A: 三步
- 提前在各oss厂商处上传处理路径参数的html,并设置oss路由解析规则
- 后台接收前端传递的活动id与用户id
- 调用短链服务生成短链地址, 将短链通过接口的形式返回给前端
参数解析html与oss相关配置
这里参数解析我们仅演示针对ua的判断及动态生成二维码的伪代码,oss相关配置以阿里云为例,这里我们以前端动态创建图片二维码来进行实现,真实情况有可能是前端通过一系列参数直接拼接地址,获取后台动态生成好的图片。
- 已经上传到oss内的参数解析html ua判断与动态生成二维码
<script>
var u = navigator.userAgent;
var ua = navigator.userAgent.toLowerCase();
// 判断是否在微信内置浏览器打开
if(ua.match(/MicroMessenger/i) == "micromessenger"){
createQrImage()
} else {
// 判断安卓
if (u.indexOf("Android") > -1 || u.indexOf("Linux") > -1) {
dosomething()
// 判断iOS
} else if (!!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)) {
dosomething()
}
}
// 生成二维码的伪代码
function createQrImage () {
let search = location.search
根据返回的路径参数,拆分uid与activityId
if(search) {
let str = search.split('?')[1]
let uid = str.split('=')[1]
let activityId = str.split('=')[0]
// 异步生成二维码base64
doQr().then(res => {
document.body.html = res
})
}
}
async function doQr () {...}
function dosomething () {
alert('nonono')
}
</script>
- oss内的相关配置
首先就是要配置静态页的规则,默认首页以及404页的处理,以及404之后的重定向
然后还需要配置允许跨域相关的处理
通过上面的两步,我们就已经完成了落地页的实现,通过基于代码的判断,动态创建html,很大程度上避免了机器扫描导致的域名拦截
用户id+活动id 生成图床地址
前端通过点击按钮触发接口调用,传递参数为uid及activityId
$('.btn').click(createUrl)
function createUrl () {
let activityId = '624EA4B'
let uid = 'nYXbXL82L822f'
fetch("https://zhen.juele.com/createUrl?activityId="+activityId+'&uid='+uid, {
"headers": {
},
"mode": "cors",
"credentials": "omit"
}).then(res => res.json()).then(res => {
document.body.innerHTML = res.data.url
})
}
后端接收参数,随机返回oss地址,为什么是随机返回呢,因为访问量大的情况下,即使通过短链,依然会有被拦截的风险,所以我们可以集成多个oss的服务,随机返回oss防封落地页地址+参数,这里我们依然通过伪代码的方式来呈现相关的内容
const express = require('express')
const app = express()
const port = 3000
// oss资源池
let ossurl = [
'aa.oss',
'bb.oss',
'cc.oss',
'dd.oss',
]
app.get('/createUrl', (req, res) => {
let activityId = req.query.activityId
let uid = req.query.uid
// 随机拼接的oss资源地址
let url = oss[Math.ceil(Math.random()*oss.length)] + ?"+activityId+'='+uid
// 调用生成短链接口
http.get('sort.cn', function (resp) {
let rawData = '';//定义一个字符变量
resp.on('data', (chunk) => { rawData += chunk; });
resp.on('end', function (err) {
if (!err) {
let sortURL = rawData
res.send(JSON.string({url: sortURL}))
}
})
})
})
梳理总结
我们再梳理一下步骤
- 首先我们需要准备的是多个oss对象存储实例,然后将我们的活动文件以index.html的名字进行上传
- 在活动页获取参数,调后台接口
- 接口中获取参数,从oss资源池生成长链【这里拼夕夕应该还有一步处理就是 针对同一用户同一活动,应该是做了一层缓存,之后会直接走命中的缓存而不再继续去随机生成长链】
- 长链转短链 【这一步 应该也会做一层缓存,因为短链很可能也有一个池子】
- 前端接收返回,页面进行展示
到这里我们的模拟落地页防封实现就已经结束了,真实的业务处理只会比现在还复杂,我们没有考虑到服务可用的情况,以及redis缓存的建立等等,但是作为模拟来说,上面的内容应该已经足够说清楚原理了。
这里我留一个课后作业
既然已经做了oss对象存储了,那为什么不将oss通过cdn进行托管,从而降低流量访问的费用呢?
tips: 通过cdn访问的流量费用要远远低于直接访问oss地址,一个叫cdn下行流量 大概在180/年/TB,oss的下行流量在6000/年/TB