28.2.26 |
15
nhận xét
|
lượt xem
Giới thiệu
- “Báo lỗi” trong từng bài viết
- Tự động lấy URL và tiêu đề bài viết
- Chuyển sang trang báo lỗi
- Gửi dữ liệu về Telegram
- Có captcha + chống spam
- Free 😁
Phần 1: Tạo API bảo mật bằng Cloudflare Worker
Bước 1: Vào Cloudflare → Compute → Workers & Pages → Create application → Chọn "Start with Hello World!" → Deploy
Bước 2: Edit code và Dán code sau:
export default {
async fetch(request, env) {
const origin = request.headers.get("Origin");
const corsHeaders = {
"Access-Control-Allow-Origin": origin || "*",
"Access-Control-Allow-Methods": "POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
"Content-Type": "application/json"
};
if (request.method === "OPTIONS") {
return new Response(null, { headers: corsHeaders });
}
if (
origin &&
!origin.endsWith("vncoding.com")
) {
return new Response(
JSON.stringify({ error: "Forbidden" }),
{ status: 403, headers: corsHeaders }
);
}
if (request.method !== "POST") {
return new Response(
JSON.stringify({ error: "Method Not Allowed" }),
{ status: 405, headers: corsHeaders }
);
}
const body = await request.json();
const {
title,
errorType,
content,
email,
imageUrl,
pageUrl,
userAgent,
secret
} = body;
if (secret !== env.FORM_SECRET) {
return new Response(
JSON.stringify({ error: "Unauthorized" }),
{ status: 401, headers: corsHeaders }
);
}
const botToken = env.TELEGRAM_TOKEN;
const chatId = "-YOUR_CHAT_ID";
const ip = request.headers.get("CF-Connecting-IP") || "Unknown";
const dateTime = new Date().toLocaleString("vi-VN");
const message = `
🚨 BÁO LỖI WEBSITE
Tiêu đề: ${title}
Loại lỗi: ${errorType}
Nội dung:
${content}
Email: ${email}
Trang: ${pageUrl}
Thiết bị: ${userAgent}
Ảnh: ${imageUrl || "Không có"}
IP: ${ip}
Thời gian: ${dateTime}
`;
await fetch(`https://api.telegram.org/bot${botToken}/sendMessage`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
chat_id: chatId,
text: message
})
});
return new Response(
JSON.stringify({ success: true }),
{ headers: corsHeaders }
);
}
};
Thay vncoding.com thành domain của bạnThay -YOUR_CHAT_ID thành chat ID telegram của bạn. Nếu chưa biết có thể tham khảo bài viết này
Bước 3: Thêm Variables trong Worker:
Chọn tab "Settings" → Tại "Variables and Secrets" click button "Add" sau đó nhậpTELEGRAM_TOKEN = Token bot của bạn
Hướng dẫn cách lấy API TOKEN tại đâyFORM_SECRET = chuoi_bi_mat
Phần 2: Thêm nút “Báo lỗi” trong bài viết
<button onclick="vncodingGoToReport()">🚨 Báo lỗi</button>
<script>
function vncodingGoToReport(){
const currentUrl = window.location.href;
let articleTitle = "";
const h1 = document.querySelector("h1");
if(h1){
articleTitle = h1.innerText.trim();
}else{
articleTitle = document.title;
}
const reportPage = "/p/bao-loi.html";
const finalUrl =
reportPage +
"?url=" + encodeURIComponent(currentUrl) +
"&title=" + encodeURIComponent(articleTitle);
window.open(finalUrl, "_blank", "noopener,noreferrer");
}
</script>
/p/bao-loi.html chính là link của trang báo lỗi
Phần 3: Tạo trang báo lỗi /p/bao-loi.html
Thêm phần hiển thị thông tin bài viết:
<h2>🚨 Báo lỗi bài viết</h2>
<div class="vncoding-article-info">
<p><strong>📄 Bài viết đang báo lỗi:</strong></p>
<p id="vncoding_display_title" class="vncoding-title"></p>
<p><strong>🔗 Link bài viết:</strong></p>
<p>
<a id="vncoding_display_url" href="#" target="_blank"></a>
</p>
</div>
<div class="vncoding-report-wrapper">
<select id="vncoding_type">
<option value="Bản quyền nội dung">Bản quyền nội dung</option>
<option value="Nội dung sai sự thật">Nội dung sai sự thật</option>
<option value="Lỗi hiển thị giao diện">Lỗi hiển thị giao diện</option>
<option value="Link hỏng (404)">Link hỏng (404)</option>
<option value="Lỗi trên mobile">Lỗi trên mobile</option>
<option value="Không đăng nhập được">Không đăng nhập được</option>
<option value="Khác">Khác</option>
</select>
<textarea id="vncoding_content" placeholder="Mô tả chi tiết lỗi"></textarea>
<input type="email" id="vncoding_email" placeholder="Email liên hệ">
<input type="url" id="vncoding_image_url" placeholder="Link ảnh minh họa (nếu có)">
<div class="vncoding-captcha-box">
<span id="vncoding_captcha_question"></span>
<input type="text" id="vncoding_captcha_answer" placeholder="Nhập kết quả">
</div>
<button id="vncoding_sendBtn" onclick="vncodingSendReport()">
Gửi báo lỗi
</button>
<p id="vncoding_msg"></p>
</div>
<style>
.vncoding-article-info{
background:#f5f7fa;
padding:15px;
border-radius:8px;
margin-bottom:20px;
border-left:4px solid #007bff;
}
.vncoding-title{
font-size:18px;
font-weight:600;
margin-bottom:15px;
}
.vncoding-report-wrapper input,
.vncoding-report-wrapper select,
.vncoding-report-wrapper textarea{
width:100%;
padding:12px;
margin-bottom:12px;
border:1px solid #ddd;
border-radius:8px;
font-size:14px;
}
.vncoding-report-wrapper textarea{
min-height:120px;
resize:vertical;
}
.vncoding-report-wrapper button{
width:100%;
padding:14px;
border:none;
border-radius:8px;
background:linear-gradient(90deg,#007bff,#0056ff);
color:white;
font-size:15px;
cursor:pointer;
}
.vncoding-captcha-box{
display:flex;
gap:10px;
}
#vncoding_msg{
margin-top:10px;
font-weight:bold;
text-align:center;
}
</style>
<script>
const WORKER_URL = "https://api.ten-worker-cua-ban.workers.dev/";
const FORM_SECRET = "chuoi_bi_mat";
let captchaResult = 0;
let lastSendTime = 0;
function getQueryParam(name){
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get(name);
}
function generateCaptcha(){
const a = Math.floor(Math.random()*10)+1;
const b = Math.floor(Math.random()*10)+1;
captchaResult = a + b;
document.getElementById("vncoding_captcha_question").innerText =
"Mã kiểm tra: " + a + " + " + b + " = ?";
}
window.onload = function(){
const articleUrl = getQueryParam("url");
const articleTitle = getQueryParam("title");
if(articleUrl){
const decodedUrl = decodeURIComponent(articleUrl);
document.getElementById("vncoding_display_url").innerText = decodedUrl;
document.getElementById("vncoding_display_url").href = decodedUrl;
window.currentArticleUrl = decodedUrl;
}
if(articleTitle){
const decodedTitle = decodeURIComponent(articleTitle);
document.getElementById("vncoding_display_title").innerText = decodedTitle;
window.currentArticleTitle = decodedTitle;
}
generateCaptcha();
};
async function vncodingSendReport(){
const now = Date.now();
if(now - lastSendTime < 60000){
document.getElementById("vncoding_msg").innerText =
"Vui lòng chờ 60 giây trước khi gửi lại.";
return;
}
const pageUrl = window.currentArticleUrl || "";
const autoTitle = window.currentArticleTitle || "";
const typeEl = document.getElementById("vncoding_type");
const contentEl = document.getElementById("vncoding_content");
const emailEl = document.getElementById("vncoding_email");
const imageEl = document.getElementById("vncoding_image_url");
const captchaEl = document.getElementById("vncoding_captcha_answer");
if(!typeEl || !contentEl || !emailEl || !captchaEl){
console.error("Thiếu ID trong form");
return;
}
const type = typeEl.value;
const content = contentEl.value.trim();
const email = emailEl.value.trim();
const imageUrl = imageEl ? imageEl.value.trim() : "";
const captcha = captchaEl.value.trim();
if(!content || !email){
document.getElementById("vncoding_msg").innerText =
"Vui lòng nhập đầy đủ thông tin.";
return;
}
if(parseInt(captcha) !== captchaResult){
document.getElementById("vncoding_msg").innerText =
"Mã kiểm tra không đúng.";
generateCaptcha();
return;
}
const btn = document.getElementById("vncoding_sendBtn");
btn.disabled = true;
btn.innerText = "Đang gửi...";
try{
const res = await fetch(WORKER_URL,{
method:"POST",
headers:{ "Content-Type":"application/json" },
body: JSON.stringify({
title: autoTitle,
errorType: type,
content,
email,
imageUrl,
pageUrl,
userAgent: navigator.userAgent,
secret: FORM_SECRET
})
});
if(res.ok){
document.getElementById("vncoding_msg").innerText =
"Gửi thành công!";
contentEl.value="";
emailEl.value="";
if(imageEl) imageEl.value="";
captchaEl.value="";
generateCaptcha();
lastSendTime = Date.now();
}else{
document.getElementById("vncoding_msg").innerText =
"Có lỗi xảy ra.";
}
}catch(e){
document.getElementById("vncoding_msg").innerText =
"Không thể kết nối máy chủ.";
}
btn.disabled=false;
btn.innerText="Gửi báo lỗi";
}
</script>
https://api.ten-worker-cua-ban.workers.dev/ thay bằng link Worker của bạn
🎯 Kết quả
- Người dùng đang đọc bài viết
- Click “Báo lỗi”
- URL + Tiêu đề được tự động điền
- Gửi lỗi về Telegram
🔐 Bảo mật
- Không lộ Bot Token
- Chống spam
- Gửi kèm IP + thiết bị
Hãy để lại bình luận bên dưới nếu bạn gặp khó khăn trong quá trình thực hiện 👇








tên miền mới trông tây hẳn nhưng logo chữ V nhìn lạ mắt cảm giác không sịn bằng chữ B như trước
REPLY DELETEHa ha. Không có ý tưởng gì thì cứ lấy chữ cái đầu tiên của tên miền làm logo luôn cho nhanh 🤣
REPLY DELETETưởng anh em blog không lên bài thôi hóa ra là anh em đều off blog hết rồi, chả thèm đọc comment
REPLY DELETEAi hoạt động vẫn hoạt động mà
REPLY DELETECoi như blog để lưu lại kiến thức sau tìm lại cho dễ 😁
Hay quá bro <3
REPLY DELETEAnh ra cái cảnh báo cấm reup bài đăng dưới mọi hình thức "kể cả ghi nguồn" đi ạ. Chứ nhiều bên reup lại mấy bài đăng gần đây rồi.
REPLY DELETECấm thế nào được họ em. kệ đi, càng nhiều người biết 😁
REPLY DELETEHay nha! Nay mới có thời gian vô blog lại. Năm mới nhiều sức khỏe nha!
REPLY DELETECảm ơn nha! Năm mới phát tài phát lộc, nhiều sức khỏe và bình an!
REPLY DELETENhận xét này đã bị tác giả xóa.
REPLY DELETEhttps://res.cloudinary.com/dl8foncmx/image/upload/f_auto,q_auto/v1772768492/hayrg5iimy07elxl3b9t.png
REPLY DELETEa thay đổi domain nữa hả a?
Xem chính xác có đúng a không? ID nó khác mà 😁
REPLY DELETEFake đấy
Thế này e cũng có một ý tưởng thú vị về liên kết dạng tự động cập nhật liên kết muốn đổi từ quản trị viên, nhưng bắt buộc phải xác thực đúng chủ blog thì trên trang blog liên kết sẽ tự động thay đổi, liên kết, và việc xác thực phải trùng với id blog đã cài đặt sẳn nè, rồi từ đó sẽ tự động cập nhật liên kết nếu gửi yêu cầu lên trang webs á, đó là snghi của em, còn việc phát triển hệ thống ra sao e chưa nghĩ ra a :D
REPLY DELETENhư thế thì khó, nhưng từ ý tưởng như này có thể setup như sau:
REPLY DELETE- Mỗi khi liên kết với blog/website của một người nào đó ta sẽ lưu ID của người đó
- Sau đó gắn một icon cho những ai đã liên kết với mình vào sau tên của họ khi comment 😁
Như vậy có thể phân biệt được là người để lại comment có phải đang liên kết với mình không