[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tKYnUdkJ-1665463185652)(zucc.png “ZUCC”)]
代码 后端 egg js
最终报告 以上部分自己删除
项目分工表格
项目自我评估表
frp使用教程(转) - 简书 (jianshu.com)
响应式编程(Reactive Programming)介绍 - 知乎 (zhihu.com)
FRP(函数时 反应式编程,不是公网穿透啊,那没事了
没有内网穿透,放在阿里云上了,直接公网
给 MQTTX项目提了一个issue,虽然没写代码,而且和我的项目没啥关系,但是他是个ts项目,也是electron跨平台的,而且我觉得我的这个issue是关于数据量大的时候性能改进的,虽然我没写代码,但是我觉得我想法还可以,也去看了源码,不知道能不能在老师这加点印象分
When the data volume exceeds 7000, mqttx will become abnormally stuck · Issue #914 · emqx/MQTTX (github.com)
响应式编程 ,on 什么的应该就是响应式吧,http库的使用
http.get(wz, function (res) {
res.on("data", function (chunk) {
strHtml += chunk;
})
res.on("end", function () {
var $ = cheerio.load(strHtml);
函数式 cheerio爬虫,函数当参数,函数连续点,应该就是函数式了
let title = $(" h2 > a",titleDiv).text()
技术点 | 自评等级:(1-5) | 备注 |
---|---|---|
FRP(函数式 反应式编程 | 1 | 没有吧 |
session Storage | 1 | 无状态没有session |
响应式编程 | 3 | http库的使用 |
函数式编程 | 3 | cheerio爬虫 |
xx 框架 | 5 | egg.js |
ORM 工具 | 4 | egg.js 的mysql |
Graph QL | 1 | 这好像是前端直接sql,我没有 |
cheerio爬虫 | 5 | |
后台轮询 | 5 | |
got reqPromise https http 请求 | 4 | 调试了多种请求库 |
pm2部署服务器 | 4 | |
防抖 | 3 | |
上传图片 fs 文件操作、删除等 | 4 | |
超时函数 | 3 |
项目说明
项目 是基于现有的egg-demon代码
starplatinum111/egg-demon (gitee.com)
他的项目作为demo,egg的框架有了,但是业务逻辑都是我自己写的
可见项目文档
https://acc15t4bm5.feishu.cn/docs/doccnLnginRRAuyalHbuiCevYhf
运行视频 https://www.bilibili.com/video/bv1zr4y1q7NC
http://starplatinumora.top:8086/ 在线预览
图片 https://acc15t4bm5.feishu.cn/docs/doccnzg9HsaG6pP0QQEmDrRxuug
可以是手机版本的,界面是按照手机版的界面分辨率做css的
一开始是我自己想做的一个小工具,因为GitHub访问慢嘛,我就希望把他的数据cache下来,放在自己服务器,不就快了嘛,想法很简单,但是我觉得效果不错。当时我先拿SpringBoot写的,后来听说这节课要拿NodeJs写后端,我看刚好合适,就改技术栈,用egg.js 写后端,拿来当作大作业了
github本身不稳定,有时候加载10s都是有的,挺常见的,但是我这个用的github API,首先他不请求前端,已经快了,然后我再缓存自己服务器,那更快了,不用去访问国外服务器了。issues我本身是不缓存的,直接github API拿,也挺快的,一页一秒钟应该是可以出来的
因为github慢很多的原因是前端的资源,js,css啊啥的,是从各种cdn里拿来的,但是有些被墙了,所以很慢,然而github本身没有被墙,所以他的后端api还是挺快的。然后还有个特点,github仓库的仓库名和描述是不容易改的,所以他的数据缓存也问题不大,他的一致性要求不高,所以哪怕一个礼拜删一次缓存,那也没关系,不像秒杀啊啥的,需要高一致性,毕竟是钱,搞错了一个订单都不行。
还有就是api不设防,直接跨域,所以直接axios请求就行,不像知乎,参数都是加密的,没办法请求,毕竟他的内容都是可以用来赚钱的,数据为王,本来就是商业性的,这挺正常的。如果能解决这个加密问题,我觉得别说毕设了,拿个博士论文应该问题不大吧。那这个api开源的好处就是可以很简单的使用,我做起来也方便。所以我觉得这个题目很适合我来做课设。
公司规定所有接口都用 post 请求,这是为什么? - 知乎 (zhihu.com)
解决技术要点说明
egg.js 打包后台 部署 https://blog.csdn.net/qq_35241223/article/details/97306900
cnpm install pkg -g
本来想要pkg 打包为 可执行文件 ,部署到服务器上的,但是踩了很多坑。后来发现这种想法是不对的,js的服务应该直接源代码扔到服务器上,cnpm install,然后拿pm2跑服务
过程错误可见
https://acc15t4bm5.feishu.cn/docs/doccn0a4VbMf2GDg0JE5kLLErxc
打包失败
https://acc15t4bm5.feishu.cn/docs/doccnE5zeKRbx0Y9i3ReMcukyfb
https://acc15t4bm5.feishu.cn/docs/doccnFp7PwLdygo0fUnykeedicd
cheerio 在一个元素基础上查询
请问我在查询到一个元素之后,再在这个元素的基础上查询应该怎么做呢。比如在java里用 jsoup 是这样实现的。搜索了repoLis,然后遍历这个lis ,每个元素里面再通过elementLi.select查找
Elements repoLis= newDoc.select("#js-pjax-container > div > div.col-12.col-md-9.float-left.px-2.pt-3.pt-md-0.codesearch-results > div > ul > li");
Listlist=new ArrayList<>();
for (Element elementLi : repoLis) {
Elements repo1Dom = elementLi.select("div.mt-n1.flex-auto");
但是在cheerio 里面就不知道怎么弄了,也没有代码提示。。
感觉这样也不对。。
let repoLis = $("#js-pjax-container > div > div.col-12.col-md-9.float-left.px-2.pt-3.pt-md-0.codesearch-results > div > ul > li");
repoLis.each((idx, item) => {
let repo1Dom = $(item).$("div.mt-n1.flex-auto")
console.log(repo1Dom.text());
})
我知道了 这样应该可行 let title = $(" h2 > a",titleDiv).text(), 第二个参数是从这个root开始找
getBaidu:function(query, page) {
const wz = "http://cn.bing.com/search?q=%E7%99%BE%E5%BA%A6&cvid=26d0fce0bc27499b9eabc8bec30cc1b9&aqs=edge..69i57j0l4j69i61l3j69i65.894j0j1&pglt=43&FORM=ANNTA1&PC=U531"; //网址
var strHtml = "";
var results = [];
http.get(wz, function (res) {
res.on("data", function (chunk) {
strHtml += chunk;
})
res.on("end", function () {
var $ = cheerio.load(strHtml);
let titleDiv = $("#b_results > li:nth-child(1) > div.b_title");
let title = $(" h2 > a",titleDiv).text()
// 这样应该是可行的
console.log("title");
console.log(title);
});
})
},
因为js类型系统还是差了点,不像java代码即是文档,js的api文档查不到就很难写,当时花了很多时间去查资料,还有自己试代码
因为 rp 是没有timeout参数的,或者说我文档里没找到,然后就找了个超时用的函数,这个我觉得挺通用的,挺好
因为是两个promise 竞赛,所以要用 const rp = require(‘request-promise’); 这个库,返回的是promise
function waitWithTimeout(promise, timeout, timeoutMessage = 'timeout') {
let timer;
const timeoutPromise = new Promise((_, reject) => {
timer = setTimeout(() => reject(timeoutMessage), timeout);
});
// race 他俩比赛,谁先成功就干啥 ,因为timeoutPromise 设置了超时之后返回超时的信息
// 所以外面接到他超时的字符串就是超时啦,虽然说也不是很优雅吧,因为万一不超时的时候也返回这个字符串呢,
// 但是这种情况很少见 , 或者说只要只要你把timeoutMessage写成一个很乱的,不可能是正常返回的东西,那他就是准确的
return Promise.race([ timeoutPromise, promise ])
.finally(() => clearTimeout(timer)); // 别忘了清 timer
}
github 是https的,所以http不能请求,需要用https
const http = require(‘http’);
const https = require(‘https’);
cheerio最后不能是空格
const topics = $(' div:nth-child(3) > div:nth-child(1) > a', repo1Dom);
正确
const topics = $(' div:nth-child(3) > div:nth-child(1) > a ', repo1Dom);
错误
repoLis.each((idx, item) => {
const repo1Dom = $('div.mt-n1.flex-auto', item);
利用浏览器 方便的获取 xpath路径
爬虫获取路径_哔哩哔哩_bilibili
写了一个mysql save函数,JPA用多了, save还是爽的,搜出来了就更新,搜不出来就插入
const MySqlUtil = {
async save(mysql, tableName, obj) {
const firstById = await mysql.get(tableName, {
id: obj.id,
});
if (firstById === null) {
return await mysql.insert(tableName, obj);
}
return await mysql.update(tableName, obj);
},
};
一个典型的 axios请求Global.axiosUrl 写在一个类里,其他地方都是调用他,这样改api位置了只要改一处,codeError 也是Global里定义
axios
.post(Global.axiosUrl + "issue/issues", data, jsonDic)
.then((response) => {
if (response.data.port === codeError) {
// this.$message.error('账号或者密码有误');
ElMessage.success("账号或者密码有误");
} else {
this.tableData = response.data.data;
console.log("this.tableData");
console.log(this.tableData);
}
})
.catch(function (error) {
console.log(error);
});
因为点击获取issues 万一点击了很多次呢,万一一秒钟点击10次,请求太多,不好的,所以要防抖,隔了几秒才能发请求
getIssues() {
if (this.canHit) {
this.getIssuesDo();
// 防抖
this.canHit = false;
var auth_timetimer = setInterval(() => {
// this.timer--;
this.canHit = true;
clearInterval(auth_timetimer);
}, 1000);
}
上传图片
https://acc15t4bm5.feishu.cn/docs/doccnWpEyPaLRAMcRzpTQNVcTyc
数据库字符集
https://acc15t4bm5.feishu.cn/docs/doccnHsCJTYHWkeOBbIepRLQ00e
pm2 log 打印
https://acc15t4bm5.feishu.cn/docs/doccnAJoVJG3F5vpSaFXiJtYZnG
nodejs 报错
https://acc15t4bm5.feishu.cn/docs/doccnAfMDDr0TIpTcBWL1UKBY5c
delete
let id=ctx.params.id
axios.delete(`${Global.axiosUrl}img/delete/${img.id}`, {id:img.id}).then((res) => {
console.log("res");
console.log(res);
});
w
fs.unlink(target,function(error){
if(error){
console.log(error);
return false;
}
console.log('删除文件成功');
})
心得体会(结合自己情况具体说明)
大项目开发过程心得
cnpm i egg-bus --save
cnpm install --save request-promise
因为库没有 的话 貌似是要重新 run dev的 ,当你启动了这个项目之后,cnpm i 了新的东西,应该是没办法使用的,需要重新run dev,新的库才会被编译
egg 报错不是很好,mysql ip 密码之类写错了,启动会失败,但是他的报错不明确
yarn 各种bug 目前觉得bug最少的还是cnpm,虽然有时候也会有bug吧
https://acc15t4bm5.feishu.cn/docs/doccnyPetglOT7BjKWiRAKsT0eh
爬虫想扔到消息队列里去的,但是egg-bus没有调通。因为关键词查询仓库的接口github好像是没有给的,只能get他的html然后爬虫他的网页数据,但是这意味着他的前端也要拿到了,所以失败率非常高,基本5次能抓取到一次就很好了,而且很慢,所以要异步的放到队列里去做。
https://acc15t4bm5.feishu.cn/docs/doccniNDEZ5CRu2swLEPxoaEPLf
我是写了个"线程"去让他反复做耗时操作,虽然js没有线程 但是我给他这样取名了
class WhileReqThread {
因为他是异步的,用起来跟java的线程很像,这样理解是很方便的
每秒去尝试执行一次,如果次数超过5次,就不做了
if (that.times < that.tryTimes) {
// reject("error times out")
return;
}
setTimeout(() => {
that.tryTimes++;
that.reqTry(urlStr);
}, 1000);
本课程建议
计算的本质太难了,calcuslas 、lambda表达式都很难,虽然挺有意思的,但是要理解一个东西都需要很长时间,而且面试也不会考,找工作没用,所以不是很希望花时间在这里,比较适合计算机科学家去研究,而不是应用型大学来学,希望能让有钱人去学这个东西,因为先富带动后富,就是让有钱人,对于生活无忧的人,去研究科学,去发展生产力,去提高国家实力,然后不要和穷人、打工仔来卷前后端,这样穷人有工作,能过活,有钱人可以发展国家,多好啊。而不是有钱人、读书好的人,去卷考公,当了公务员也不知道在干嘛
挺合理的
有意思 但是难,画的时间多,不适合应用型大学,找工作计算的本质应该不太有用,应该卷面经,vue的diff算法,js的Promise啥的,其实也是学了吧,其实还是有点像面经的,
怎么说呢,以后找个955的工作空闲时间学学计算的本质、编译器啥的,还挺有意思,996就算了,没时间学,现在上学期间忙着找工作,也没时间学
资源很好 很多,放在网站上自己看,很舒服。其实我希望今年讲过的课,有学在城院的视频,可以直接给下届的同学看就行了,可以快进,返回去看,反复看,多好啊,上课可以让同学来问问题,上课可以不讲课了,可以去github上逛,搜集更多的好的资料给同学,不是更好吗
不知道老师有没有兴趣看看我对好的课程的定义
什么样的老师是好老师?应该怎么样做一个好老师? - 求你别让我写论文的回答 - 知乎 https://www.zhihu.com/question/25026687/answer/2344876775
空闲时间学学计算的本质、编译器啥的,还挺有意思,996就算了,没时间学,现在上学期间忙着找工作,也没时间学
资源很好 很多,放在网站上自己看,很舒服。其实我希望今年讲过的课,有学在城院的视频,可以直接给下届的同学看就行了,可以快进,返回去看,反复看,多好啊,上课可以让同学来问问题,上课可以不讲课了,可以去github上逛,搜集更多的好的资料给同学,不是更好吗
不知道老师有没有兴趣看看我对好的课程的定义
什么样的老师是好老师?应该怎么样做一个好老师? - 求你别让我写论文的回答 - 知乎 https://www.zhihu.com/question/25026687/answer/2344876775