Это 18-й день моего участия в августовском испытании обновлений. Узнайте подробности события:Испытание августовского обновления.
предисловие
Играть в Наггетссерия, расширяющая некоторые интересные функции для Nuggets, такие как:
- [Игра с наггетсами] Статья в колонке о наггетсах создает документ в формате pdf
- [Playing with the Nuggets] Автор контракта Nuggets, анализ параметров боевой мощи, статьи с данными
Однажды, зайдя на свою личную домашнюю страницу, я увидел, что она мне уже понравилась другим.千
Да, я бросаю Бога.
Как новички, это нормально поддерживать друг друга Кому эти 💗 мои даны, добивайтесь реального образа и реализуйте его сами.
Демонстрация эффекта
Подробный список можно щелкнуть, чтобы перейти на страницу статьи.
Адрес источника
Адрес источника:JJMyStarAndC
Серверная служба написана на nodejs, и вам необходимо установить соответствующий установочный пакет.
Реализовать идеи
Возможные идеи:
- Плагин Chrome + скрипт обезьяны
- Статические страницы + прокси nginx
- Статическая страница + переадресация услуги
- ......
Идея этой статьи заключается в静态页面
+ nodejs自定义服务
,
Просто дополнительно для удовольствияServer Sent Events, называемая SSE, односторонняя отправка на стороне сервера,Его функция заключается в том, что после того, как сервер получит данные, он в одностороннем порядке отправляет их в службу поддержки клиентов.
Некоторые люди могут сказать, почему бы и нетsocket.io
, позвольте мне сказать кое-что здесь,socket.io
Так называемый jQuery в сокете, все понимают, что это значит, и его нужно использовать вместе с его серверной библиотекой, ненавижу его! !
Лучшее решение: прозрачная передача
express
+ http-proxy-middleware
детали реализации
сбор информации
Все крутится вокруг данных, если данных нет, не надо делать торты и говорить об идеалах.
Для приобретения Звезды достаточно одного интерфейса!
Адрес запроса: API.Nuggets.Talent/interact_AP…
Метод запроса: post
Параметры запроса:
Это скрытоlimit
Как насчет вариантов параметров? Каждый может попробовать!
{
cursor: `${cursor}`, // 起始查询位置
item_type: 2, // 文章点赞,对应有沸点点赞
sort_type: 2, // 排序,有近导员
user_id: uid, // 用户id
}
Возвращаемый результат:
{
has_more: true,
data: [{
author_user_info:{
user_id: "3465271329953806", // 用户ID
user_name: "小魔童哪吒" // 用户名
},
article_info: {
article_id: "6996484371305725965" // 文章ID
title: "k8s 学习二" // 文章标题
}
}]
}
при запросе,cursor
Очень важный параметр, указывающий положение указателя, откуда продолжать идти назад.
В возвращаемом результате очень важные поляhas_more
, указывает на то, что данных еще нет, если они есть, продолжайте сбор.
В самородках очень много интерфейсов, и ограничений поначалу не было, в начале помню, что некоторые интерфейсы можно передать.limit
Параметр 1000, тоже нормально, позже его доработали, что достойно похвалы.
Его цикл получает основной код:
while (res.has_more) {
data.cursor = `${cursor}`
res = (await axios.default.post(url, data, {
headers
})).data;
cursor += 10;
await delay(undefined, 16).run(); // 暂停16ms, 故意的
}
Мы сказали, что вот данные, полученные сервером, но они не были переданы во внешний интерфейс.
передача данных
Использовать SSE на стороне nodejs тоже очень просто, здесь я не буду использовать стороннюю библиотеку.
- запрос прошел uid, избавился от двух параметров uid означает идентификатор пользователя, rid означает requestId
-
getStars
Указывает на запуск запроса - Суть SSE заключается в
Content-Type
а такжеConnection
'Content-Type': 'text/event-stream'
Тип объявления
'Connection': 'keep-alive'
Указывает, что соединение не закрыто - Поскольку это тоже запрос, мы используем центр событий для отправки событий в запрос, а запрос записывает обратно данные
app.get('/sseStream', function (request, response) {
response.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
const { uid, rid } = request.query;
console.log("uid:", uid);
// 查询用户的点赞
getStars(uid, rid);
// 产线可别这么用
eventsCenter.removeAllListeners("ssePush");
// 事件中心
eventsCenter.on("ssePush", function (event, data) {
// console.log("push message to clients");
response.write("event: " + String(event) + "\n" + "data: " + JSON.stringify(data) + "\n\n");
});
});
Куда отправляется событие, то есть куда отправляется сбор данных, добавлю код, тут еще два событияmessageTotal
, messageEnd
, одно — это общее сообщение, а другое — это сообщение, указывающее на завершение запроса.
async function getStars(uid, rid) {
let cursor = 0
const data = {
cursor: `${cursor}`,
item_type: 2,
sort_type: 2,
user_id: uid,
}
let res = {
has_more: true
};
while (res.has_more) {
data.cursor = `${cursor}`
res = (await axios.default.post(url, data, {
headers
})).data;
console.log("res:", data, res)
eventsCenter.emit("ssePush", "messageTotal", {
uid,
rid,
count: res.count
});
eventsCenter.emit("ssePush", "message", {
uid,
rid,
datas: (res.data || []).map(d => ({
user_id: d.author_user_info.user_id,
user_name: d.author_user_info.user_name,
title: d.article_info.title
}))
});
cursor += 10;
await delay(undefined, 16).run();
}
eventsCenter.emit("ssePush", "messageEnd", {
uid,
rid
})
}
Сбор данных переднего плана
Передний план соответствует событию мониторинга, это так просто.
const source = new EventSource(`/sseStream?uid=${uid}&rid=${rid}`);
// 收到新数据
source.addEventListener('message', function (e) {
let data = JSON.parse(e.data)
// 不是需要的数据
if (data.uid != uid || data.rid != rid) {
return;
}
listArr.push(...data.datas);
// console.log("listArr:", listArr);
renderList(listArr);
gotStarsEl.innerHTML = listArr.length;
}, false)
// 收到总数据消息
source.addEventListener('messageTotal', function (e) {
let data = JSON.parse(e.data)
// 不是需要的数据
if (data.uid != uid || data.rid != rid) {
return;
}
totalStarsEl.innerHTML = data.count;
}, false)
// 统计完毕
source.addEventListener('messageEnd', function (e) {
let data = JSON.parse(e.data)
console.log("meesage", data);
}, false)
Статистика и группировка
- Статистика: взять в качестве ключа ID пользователя, если нет, то создать новый, а если да, то изменить кардинальность.
- Сопоставьте ключи с массивом, а затем отсортируйте.
Это так просто!
const statObj = list.reduce((obj, cur) => {
if (hasOwnProperty.call(obj, cur.user_id)) {
obj[cur.user_id].count += 1;
obj[cur.user_id].items.push(cur);
} else {
obj[cur.user_id] = {
items: [cur],
count: 1,
...cur
};
}
return obj;
}, {});
// 分组
const groupList = Object
.keys(statObj)
.map(k => statObj[k]) //分组
.sort((a, b) => a.count > b.count ? -1 : 1); // 排序
Для получения дополнительных сведений о реализации перейдите к исходному коду.
напиши в конце
3-5 минут, 500-1000 слов, есть что набрать, но не слишком много хлопот.Если вы считаете, что это хорошо, то ваши лайки и комментарии - самая большая мотивация для меня двигаться дальше.
Пожалуйста, посетите группу технического обменаиди сюда. Или добавьте мое облако похорон WeChat и учитесь вместе.