前言
碰巧掘金新上簽到活動(dòng),碰巧喝了咖啡睡不著,碰巧雙休不用上班,所以寫了個(gè)插件,方便工作日簽到(順道練練手)
先來看看成品



總的來看,插件需要實(shí)現(xiàn)以下幾個(gè)目標(biāo):
- 檢測當(dāng)前用戶登錄態(tài)
- 判斷用戶今天是否已簽到
- 發(fā)送簽到請求
- 展示信息(用戶信息,獎(jiǎng)勵(lì)信息)

請求分析
用戶登錄憑證
通過登錄請求[POST] /passport/web/user/login可以看到,請求響應(yīng)設(shè)置的Cookie中有好幾個(gè)鍵值對,選擇一個(gè)普通的請求在postman上分析,可以看到掘金通過Cookie中的sessionid作為用戶登錄憑證

簽到相關(guān)的接口
在簽到功能的請求中,跟這次要實(shí)現(xiàn)功能相關(guān)的接口有4個(gè),分別是:
- 獲取簽到天數(shù)的匯總信息
[GET]/growth_api/v1/get_counts - 獲取當(dāng)前的礦石數(shù)量
[GET]/growth_api/v1/get_cur_point - 判斷用戶今天是否已簽到
[GET]/growth_api/v1/get_today_status - 用戶簽到
[POST]/growth_api/v1/check_in
這里大致分析一下功能對應(yīng)的請求即可,具體傳參以及返回值的含義可以通過瀏覽器控制臺查看(
F12)
流程圖
下面通過幾個(gè)場景的時(shí)序圖來闡述清楚插件的工作流程
未登錄場景

未簽到場景

已簽到場景

搭建chrome插件開發(fā)工程
通過vue-web-extension實(shí)現(xiàn)快速搭建chrome插件開發(fā)工程(Vue)
首先確保這兩個(gè)已經(jīng)安裝了
npm install -g @vue/cli
npm install -g @vue/cli-init
然后通過vue-web-extension創(chuàng)建工程,我選擇vue-web-extension的版本是v1
vue init kocal/vue-web-extension#v1 juejin-auto-sign
按需選擇自己需要的功能(axios必選)

安裝element ui(按需加載)
cd juejin-auto-sign && vue add element

由于element ui的配置會(huì)寫在package.json文件中babel部分,跟工程原有的.babelrc配置文件重疊了,需要將package.json中關(guān)于babel部分的配置合并到.babelrc文件中
合并前
# .babelrc配置文件
{
"plugins": [
"@babel/plugin-proposal-optional-chaining"
],
"presets": [
["@babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3,
"targets": {
// https://jamie.build/last-2-versions
"browsers": ["> 0.25%", "not ie 11", "not op_mini all"]
}
}]
]
}
# package.json配置文件
{
.......
"babel": {
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
}
合并后,將package.json中babel部分刪除,.babelrc配置文件如下
在工程根目錄下執(zhí)行yarn build,能夠正常打包
yarn build

至此,工程已經(jīng)基本搭建完成了!可以正式投入開發(fā)
工程常用命令:
- yarn build 構(gòu)建插件,輸出到dist目錄下
- yarn build-zip 按照插件名+版本號的形式,構(gòu)建插件壓縮包
-
yarn watch構(gòu)建插件,輸出到dist目錄下,如果發(fā)生改動(dòng),會(huì)即時(shí)刷新
關(guān)鍵代碼
manifest.json配置文件
manifest.json文件中記載著插件的原信息,其中包括插件的基礎(chǔ)信息(插件名稱,版本號,ICON等),以及插件涉及頁面(popup,options,background等),還有插件需要向chrome申請的權(quán)限
{
// 插件名稱
"name": "juejin-auto-sign",
// 插件描述
"description": "掘金簽到助手",
// 插件版本號
"version": "1.0.0",
"manifest_version": 2,
"icons": {
"48": "icons/icon.png",
"128": "icons/icon.png"
},
......
// [1] 申請掘金的cookie、網(wǎng)絡(luò)請求的權(quán)限
"permissions": [
"cookies",
"*://*.juejin.cn/",
"webRequest",
"webRequestBlocking"
]
}
[1]處可以看到,插件需要申請網(wǎng)絡(luò)權(quán)限 webRequest 和 webRequestBlocking,這兩個(gè)權(quán)限是跟用戶簽到請求有關(guān)系的(POST請求),后面會(huì)詳細(xì)介紹為什么需要這兩個(gè)權(quán)限
popup頁面
目前插件的功能實(shí)現(xiàn)都是在popup頁面,所謂popup頁面就是在瀏覽器插件欄處點(diǎn)擊展示的頁面

拿Google翻譯插件來看,紅色箭頭指向的頁面就是popup頁面
chrome插件開發(fā)有分好幾種頁面以及腳本
頁面有:popup,optional,background,插件上不同頁面的展示位置是不同,用途也不同,目前只需要了解到popup頁面即可
腳本有:background.js,content script等,不同的腳本聲明周期也是不同的
下面展示簽到助手插件popup頁面的主要代碼
<template>
<div class="sign-body">
<div class="sign-image">
<el-avatar size="large" :src="imageUrl"></el-avatar>
</div>
<div class="sign-text">{{ nickName }}</div>
<div class="sign-label">
當(dāng)前礦石數(shù)量:<el-tag size="mini" type="success">{{ currentPoint }}</el-tag>
</div>
<div class="sign-label">
連續(xù)簽到天數(shù):<el-tag size="mini" type="success">{{ continueSignDays }}</el-tag>
</div>
<div class="sign-btn" v-if="!loading">
<el-button v-if="!login" type="primary" @click="toLogin">去登錄</el-button>
<el-button v-else type="primary" :loading="signing" :disabled="todaySign" @click="toSign">{{ todaySign ? '已簽到' : '去簽到' }}</el-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
// 頭像
imageUrl: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
// 昵稱
nickName: 'null',
// 當(dāng)前礦石數(shù)量
currentPoint: 0,
// 連續(xù)簽到天數(shù)
continueSignDays: 0,
// 是否登錄
login: false,
// 今日是否已簽到
todaySign: true,
loading: true,
signing: false,
};
},
.......
async mounted() {
this.loading = true;
// 獲取用戶信息
let resp = await getUserInfo();
// 判斷cookie有效性
this.login = !resp.data.err_no && resp.data.data;
if (!this.login) {
this.loading = false;
return;
}
// 頭像,昵稱
this.imageUrl = resp.data.data.avatar_large;
this.nickName = resp.data.data.user_name;
// 礦石數(shù)量
resp = await getCurrentPoint();
this.currentPoint = resp.data.data;
// 連續(xù)簽到天數(shù)
resp = await getSignData();
this.continueSignDays = resp.data.data.cont_count;
// 當(dāng)前簽到狀況
resp = await getTodaySign();
this.todaySign = resp.data.data;
this.loading = false;
},
};
</script>
主要的邏輯都包含在頁面mounted階段,該階段需要執(zhí)行一系列操作,包括獲取用戶信息,判斷cookie有效性,獲取用戶當(dāng)前簽到狀態(tài)以及獎(jiǎng)勵(lì)信息等等
忽略<template>中的一堆笨拙的<div>標(biāo)簽,前端我只會(huì)寫<div>

修改請求頭
簽到請求/growth_api/v1/check_in是一個(gè)POST請求,瀏覽器會(huì)自動(dòng)帶上origin請求頭,其值為chrome-extension://xxxxx,此時(shí)掘金會(huì)校驗(yàn)請求頭中的origin,非掘金的origin會(huì)直接報(bào)403(應(yīng)該是網(wǎng)關(guān)層做了請求來源的校驗(yàn))

此時(shí)插件就需要修改請求頭中的origin字段,然而origin字段并不能隨意修改
比方說axios強(qiáng)制指定請求頭中origin的值是不生效的,并且插件的控制臺會(huì)有對應(yīng)的錯(cuò)誤提示,該操作不符合規(guī)范
此時(shí)就需要使用到manifest.json中注冊的網(wǎng)絡(luò)請求的權(quán)限
一個(gè)正常響應(yīng)的請求在chrome中會(huì)經(jīng)歷如下圖所示的聲明周期

如果我們需要修改請求頭字段的話,則可以在onBeforeSendHeaders發(fā)送請求頭之前通過事件監(jiān)聽的方式修改origin字段,同時(shí),該事件監(jiān)聽?wèi)?yīng)該是貫穿整個(gè)插件的生命周期的,所以代碼應(yīng)該寫在background.js中
// background.js文件
chrome.webRequest.onBeforeSendHeaders.addListener(
function(details) {
details.requestHeaders.push({ name: 'origin', value: 'https://juejin.cn' });
return { requestHeaders: details.requestHeaders };
},
{ urls: ['*://*.juejin.cn/*'] },
['blocking', 'requestHeaders', 'extraHeaders']
);
上述代碼中可以看到,chrome.webRequest.onBeforeSendHeaders.addListener接受三個(gè)參數(shù):
- 監(jiān)聽器回調(diào)方法,修改請求頭的操作應(yīng)該放在這個(gè)方法中
- 過濾器,用于控制監(jiān)聽的URL范圍,這里選擇監(jiān)聽掘金相關(guān)的請求
- 元信息(opt_extraInfoSpec),簡單來說就是,這個(gè)參數(shù)填寫的值代表監(jiān)聽器的回調(diào)方法的執(zhí)行方式以及回調(diào)時(shí)傳入的數(shù)據(jù)
本次監(jiān)聽器的元數(shù)據(jù)中包含['blocking', 'requestHeaders', 'extraHeaders'],這三個(gè)值分別表示:-
blocking表示回調(diào)方法是同步調(diào)用的,就是說一個(gè)請求的回調(diào)方法執(zhí)行完之后才會(huì)輪到下一個(gè)請求的回調(diào)方法 -
requestHeaders表示回調(diào)方法的參數(shù)details中包含請求頭的數(shù)據(jù) -
extraHeaders這個(gè)字段比較神奇,由于origin請求頭這玩意不是說改就改的,chrome也不推薦,如果真的要修改的話,就必須要填寫這個(gè)字段,這樣對origin的修改才會(huì)生效
-
在manifest配置文件中可以看到,插件申請的權(quán)限除了
webRequest之外,還有webRequestBlocking,添加這個(gè)權(quán)限是因?yàn)楸O(jiān)聽方法中使用blocking同步的方式
總結(jié)
至此,這個(gè)插件的實(shí)現(xiàn)思路基本介紹完了,總的來看,插件的實(shí)現(xiàn)難度不高,有興趣的可以自己試著嘗試實(shí)現(xiàn)一下
當(dāng)然,以插件的形式來實(shí)現(xiàn)簽到的功能其實(shí)并沒有極大幅度地提高簽到的效率,最好的方式肯定還是在服務(wù)器中定時(shí)簽到,這樣即使不上掘金網(wǎng)站,也能收獲滿滿的礦石用以抽獎(jiǎng),但是這樣不可避免地將用戶登錄憑證暴露出去,可能存在一些安全風(fēng)險(xiǎn),同時(shí)也喪失了掘金舉辦這個(gè)活動(dòng)的意義
萬一被別人拿到自己的cookie跑去刪除自己的文章,那真的是欲哭無淚
這次掘金的簽到活動(dòng)個(gè)人覺得還是辦的可以的
任務(wù)難度很低,規(guī)則簡單,活動(dòng)入口明顯
簽到獎(jiǎng)勵(lì)比較多,一個(gè)月簽到下來,應(yīng)該都有好幾千礦石,應(yīng)該能抽獎(jiǎng)好幾十次
唯一不好的地方就是我抽了好幾天都沒抽到switch,哈哈哈哈
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- 前言 周末學(xué)習(xí)了下Chrome插件的開發(fā),總體來說入門還是比較容易的,動(dòng)手配合一些demo就能了解基本的開發(fā)過程。...
- 需求背景: 最近維護(hù)一個(gè)老項(xiàng)目,沒有前端交接,文檔只有項(xiàng)目啟動(dòng)和打包說明,配合的后端也是半路接手只愿提供新接口的文...
- 1. 簡介 Chrome插件是一個(gè)用Web技術(shù)開發(fā)、用來增強(qiáng)瀏覽器功能的軟件,Chrome瀏覽器擴(kuò)展開發(fā)算是相當(dāng)簡...
- 今天青石的票圈出鏡率最高的,莫過于張藝謀的新片終于定檔了。 一張滿溢著水墨風(fēng)的海報(bào)一次次的出現(xiàn)在票圈里,也就是老謀...