我的小程序接口被刷爆了

自然流量的惊喜

      书接上文,凭着短视频的好奇,搭了个小程序,做了文案提取,配音等功能,也顺带写了两篇口水文章,不曾想居然收获历史最高的点赞与收藏。有兴趣的朋友可以点这里一看究尽:《短视频配音原来如此简单》,《短视频文案提取的简单实现》。做为一个食人间烟火的程序员,也偷偷的去看了数据,由于没抱太大的期望,自然流量给了我一个大大的惊喜,下图是没有任何推广的数据。我一度暗暗自喜,直到我上线了另一个小程序做对照组时,也就是上两个文章中提到的小程序,几乎没有自然流量,即使这个小程序功能更全,体验更好,所有用户都是从我的文章中关联而来的,没有自然流量。我瞬间明白了:论小程序取名的重要性。

告警呼啸而至

        小程序上线后,总于可以睡上安稳觉了。于是又开始早上6:30去学校带小朋友跑步了。跑了一年了,好几个小朋友算是跑上道了。跑得正酣畅淋漓之时,突然,企微告警群开始咚咚告警:resource pack exhausted! Please purchase resource packs... 30小时的资源包才买几天怎么就耗尽了呢。跑完步,在学校噌了早饭,小电驴儿一溜烟回家打开电脑,巴拉出访问日志,傻眼了。这样一个没名没份的小程序,居然有人在刷它的接口(大部分都是视频文案提取,原来还有这么多人在做短视频),心中顿感五味杂成,有人刷说明功能还不多,这样刷地主家也没有余粮了...

签名保驾护航

        既然来了,只能接招了。既然刷接口,那就对接口访问做一些校验。目前小程序只是提文案提取等功能,所以首先想到接口做个签名,防止别人使用程序自动刷。考虑小程序源码获取比较困难,签名字段根据sha1简单生成就可以了,未来如果这个也行不通,再使用RSA加密下sign字段就可以了。sign生成规则比较简单,timestamp,request,随机串,请求参数,排序 sha1就可以了。代码如下。

前端只需要在request中 生成签名,放到header里就行了。

function sign(json) {
  json.timestamp = getTimestamp();
  json.rand = mtRand(100000, 999999);
  json.appkey = app.globalData.secretKey;

  let valueArray = [];
  for (let key in json) {
    valueArray.push(json[key]);
  }
  valueArray.sort();

  let signStr = jsonVAL(valueArray);
  console.log("signStr", signStr);

  json.sign = sha1Util.sha1(signStr);
  delete json.appkey;
  return json;
}

后端也简单,根据一样的规则,一样的key,生成sign,对比前端的sign字段就可以了。自定义HandlerInterceptor,并注册到InterceptorRegistry中就。

代码如下;

/**
 * sign校验拦截器
 * @author JJ
 */
@Slf4j
@Component
public class CheckSignInterceptor implements HandlerInterceptor {

    private static final String SecretKey = "*******";
    // 签名过期时间(s)
    private static final Integer TimestampOut = 300;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {


        RequestWrapper requestWrapper = new RequestWrapper(request);
        String body = requestWrapper.getBody();
        Result result = this.check(body);
        if (!result.getSuccess()) {
            log.info("签名失败:{}", body);
            // 设置状态码为401,表示未授权
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            // 设置响应内容类型和字符集
            response.setContentType("application/json;charset=UTF-8");
            // 自定义输出
            response.getWriter().write(JSONUtil.toJsonStr(result));
            // 返回false阻止后续处理
            return false;
        }
        return true;
    }

    /**
     * token校验
     * @param token
     * @return
     */
    private Result check(String body) {

        JSONObject jsonObject = JSONUtil.parseObj(body);
        String sign = "";
        Long timestamp = 0L;
        // jsonObject 值输入有序列表。
        List<String> paramsValueList = new ArrayList<>();
        Set<Map.Entry<String, Object>> entries = jsonObject.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (key.equals("sign")){
                sign = value.toString();
                continue;
            }
            if (key.equals("timestamp")){
                //如果时间戳为空
                if (Strings.isNullOrEmpty(value.toString())){
                    return Result.failed(ErrorCodeEnum.ILLEGAL_ARGUMENT.code(), "时间戳不能为空");
                }
                timestamp = Long.parseLong(value.toString());
            }
            paramsValueList.add(value.toString());
        }
        paramsValueList.add(SecretKey);
        Collections.sort(paramsValueList);

        //判断时间是否大于5分钟
        if (System.currentTimeMillis()/1000 - timestamp > TimestampOut){
            //return Result.failed(ErrorCodeEnum.ILLEGAL_ARGUMENT.code(), "时间戳无效");
        }
        String signStr = "";
        for (String value : paramsValueList) {
            signStr += value;
        }
        log.info("signStr:{}", signStr);
        String sha1Str = SecureUtil.sha1(signStr);
        if (sha1Str.equals(sign)){
            return Result.success();
        }
        return Result.failed(ErrorCodeEnum.ILLEGAL_ARGUMENT.code(), "签名失败");
    }

}
/**
 * @author JJ
 * @Classname InterceptorConfig
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Resource
    CheckTokenInterceptor checkTokenInterceptor;
    @Resource
    CheckSignInterceptor checkSignInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(checkSignInterceptor).order(1);
       
    }
}

以上代码基本都是copy的原有代码,没半天就上线了,自以为可以高枕无忧了。

啥也挡不住RPA

       上线后,购买了资源包,也提心吊胆的统计着使用量。过了办天,又有几个用户提取了超过70条视频的文案。我一度怀疑签名没生效,直到我看非常规律的调用,我知道了,RPA来了。之前公司买过一个叫影刀RPA软件,也玩了一些时间,编写过一些自动化任务。它可以模拟人操作行为,完成自动化任务,当然,我一直认为未来RPA会有更多业务场景,一些逻辑明确的重复的事,都会由它们来完成。难怪小程序数据里有不少是从pc打开的。我意识到我被薅羊毛了。

无奈只能限量了

       本着大家都有机会体验这个小程序的原则,无奈之下,只能给每人每日限量了,毕竟小程序没有收入。再本着能每个人都有极致体验的机会,我限制了每人每天每个功能30次。这下基本上都限制到了,但是看着那些个RPA机器人,一大早就毫无感情的把30次机会耗尽,于是又增加了按UserId配置额度的功能,优先级高于按功能分配的额度。一顿操作后,总算是基本控制住了。又心累又心喜。喜在小程序给部分人带来了价值,即便是用RPA的那些人也是有价值,虽然没有感情。累的是又不得不处理这些烦琐之事。

写在最后

最近短剧火了起来,就有不少人开始提取长视频的文案以及长视频去水印。考虑到微信保存视频时,有个200M的限制,又在考虑支持视频文件压缩功能了。跟本停不下来了,把写代码当成乐趣也是不错的一件事儿。

有兴趣的同学可以扫码体验下小程序(小程序名称正在申请修改名称,建议扫码)

小程序名称 :智能配音实用工具;

小程序二维码 : 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/537262.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ZL-WK-4五孔注意力测试系统

简单介绍&#xff1a; 五孔注意力测试系统基于视觉上的辨别力&#xff0c;通过运行5-CSRTT任务(5-choice serial reaction time task)&#xff0c; 测试动物的注意力、冲动性(impulsivity)等一系列行为学指标&#xff0c;主要用于注意力缺失/多动综合症(attention deficit/hype…

若依框架判断是否关闭了某个页面,或者在关闭某个页面进行操作

src\plugins\tab.js // 关闭指定tab页签closePage(obj) {console.log(obj,obj)if (obj undefined) {return store.dispatch(tagsView/delView, router.currentRoute).then(({ lastPath }) > {return router.push(lastPath || /);});}if(obj.fullPath "/plugin/workfl…

RabbitMQ消息模型之Fanout消息模型

Fanout消息模型 * 广播模型&#xff1a;* 一个交换机绑定多个队列* 每个队列都有一个消费者* 每个消费者消费自己队列中的消息&#xff0c;每个队列的信息是一样的生产者 package com.example.demo02.mq.fanout;import com.example.demo02.mq.util.ConnectionUtils; impor…

2023年金融贷款骗局套路之一

源地址&#xff1a;2023年金融贷款骗局套路之一_预防网贷套路_计算机技术网 随着无卡消费的日夜流行&#xff0c;三年疫情出现&#xff0c;钱难寻&#xff0c;难找的尴尬境地&#xff0c;贷款骗局也出现不少。今天我们讲讲最近很流行的贷款骗局之一中的一种贷款骗局。 在平常…

C++设计模式|0.前言

1.什么是设计模式&#xff1f; 简答来说&#xff0c;设计模式就是一套好用的代码经验总结&#xff0c;也就是怎么写好代码的方法论。使用设计模式是为了可重用代码、让代码更容易被他人理解、提高代码的可靠性。 2.设计模式的分类 设计模式可以分为三类&#xff1a;创建型、…

【Unity渲染】渲染管线原理

整理自B站UPKerry佬的视频【【教程】技术美术入门&#xff1a;渲染管线概述】 https://www.bilibili.com/video/BV1Q54y1G7v3/?share_sourcecopy_web&vd_source7e6249c05fba6efe32e8867373f75917 应用阶段 、几何阶段顶点处理、光栅化、片元处理、输出合并 应用阶段是CUP…

WebSocket一篇讲清楚

文章目录 WebSocket简介WebSocket与HTTP的区别WebSocket的工作原理WebSocket的应用场景WebSocket的使用WebSocket 属性WebSocket 事件WebSocket 方法 WebSocket的心跳机制WebSocket 的安全性和跨域问题如何处理&#xff1f;有哪些好用的客户端WebSocket第三方库总结 WebSocket简…

2024年 Mathorcup高校数学建模竞赛(B题)| 甲骨文识别 | 特征提取,图像分割解析,小鹿学长带队指引全代码文章与思路

我是鹿鹿学长&#xff0c;就读于上海交通大学&#xff0c;截至目前已经帮200人完成了建模与思路的构建的处理了&#xff5e; 本篇文章是鹿鹿学长经过深度思考&#xff0c;独辟蹊径&#xff0c;通过神经网络解决甲骨文识别问题。结合特征提取&#xff0c;图像分割等多元算法&…

如何在Windows通过固定tcp公网地址ssh远程访问本地Kali Linux

文章目录 1. 启动kali ssh 服务2. kali 安装cpolar 内网穿透3. 配置kali ssh公网地址4. 远程连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 本文主要介绍如何在Kali系统编辑SSH配置文件并结合cpolar内网穿透软件&#xff0c;实现公网环境ssh远程连接本地kali系统。 1. 启…

科技云报道:大模型加持后,数字人“更像人”了吗?

科技云报道原创。 北京冬奥运AI 虚拟人手语主播、杭州亚运会数字人点火、新华社数字记者、数字航天员小诤…当随着越来越多数字人出现在人们生活中&#xff0c;整个数字人行业也朝着多元化且广泛的应用方向发展&#xff0c;快速拓展到不同行业、不同场景。 面向C端&#xff0…

appium

app元素抓取在线工具 Appium Inspector by Appium Pro appium安装&#xff08;通过node.js安装&#xff09; Python3Appium安装使用教程_python_脚本之家 Node version is 18.17.1

CST软件中变更求解器和宏的使用技巧【操作教程】

变更求解器 变更CST MWS中的Solver&#xff01; Home > Simulation > Setup Solver CST Microwave Studio (CST MWS)总共有六个Solver。用户根据仿真目的和应用方向选择合适的Solver&#xff0c;才可以快速获得准确的结果。变更或选择Solver时&#xff0c;在Setup Sol…

DNS正反向解析

1.先连接X-shell 主服务器&#xff1a;192.168.32.168&#xff08;server&#xff09; 从服务器&#xff1a;192.168.32.169&#xff08;node&#xff09; 2.给主从服务器做准备工作 [rootserver ~]# setenforce 0 setenforce: SELinux is disabled [rootserver ~]# systemc…

盲盒App开发:探索未知惊喜,解锁潮流新玩法

在追求个性和独特体验的时代&#xff0c;盲盒文化以其独特的魅力&#xff0c;迅速占领了年轻人的心。为了满足这一市场需求&#xff0c;我们倾力打造了一款全新的盲盒App&#xff0c;带你开启一段充满未知与惊喜的探索之旅。 这款盲盒App融合了创新科技与潮流文化&#xff0c;…

Point-Nerf复现

Point-Nerf复现 0.0我自己的复现工程0.1相关库介绍0.1.1 pytorch0.1.2 h5py0.1.3 Scikit-Image0.1.4 imageio 0.2.复现简介0.3.参考链接 0.0我自己的复现工程 代码和安装包下载地址   所需库的安装包在package文件夹下&#xff0c;代码在code文件夹下&#xff0c;测试数据在…

FFmpeg: 简易ijkplayer播放器实现--05ijkplayer–连接UI界面和ffplay.c

文章目录 ijkplayer时序图消息循环--回调函数实现播放器播放时状态转换播放停止 ijkmediaPlay成员变量成员函数 ijkplayer时序图 stream_open: frame_queue_init packet_queue_init init_clock 创建read_thread线程 创建video_refresh_thread线程 消息循环–回调函数实现 ui …

003Node.js创建第一个web服务

如果用PHP来编写后端代码&#xff0c;需要用Apache或者Nginx的服务器,来处理客户的请求响应。对于Node.js时&#xff0c;不仅实现了应用&#xff0c;同时还实现了整个HTTP服务器. 安装 Node Snippets插件&#xff08;编程自带提示&#xff09; console.log(你好nodejs); //表…

PyCharm远程链接AutoDL

AutoDL使用方法&#xff1a; Step1&#xff1a;确认您安装的PyCharm是社区版还是专业版&#xff0c;只有专业版才支持远程开发功能。 Step2&#xff1a;开机实例 复制自己实例的SSH指令&#xff0c;比如&#xff1a;ssh -p 38076 rootregion-1.autodl.com 在ssh -p 38076 roo…

vue点击上传图片并实现图片预览功能,并实现多张图片放到一个数组中进行后端请求(使用原生input)

一、将 File 对象转成 BASE64 字符串 &#xff08;FileReader&#xff09; <template><div><!-- 用来显示封面的图片 --><!-- <img src"/assets/images/cover.jpg" alt"" class"cover-img" ref"imgRef" />…

创新实训2024.04.11日志:self-instruct生成指令

1. 参考文献 代码&#xff1a;https://github.com/yizhongw/self-instruct论文&#xff1a;https://arxiv.org/abs/2212.10560 2. 前沿论文阅读 2.1. self-instruct技术的优势 作者在文章中提到&#xff1a; The recent NLP literature has witnessed a tremendous amount …