Nodejs实现qq空间[神奇图片]的制作原理
Nodejs实现qq空间[神奇图片]的制作原理
相信很多人都看到过qq空间转发的某条日志中有张神奇图片 会显示你的头像,个人qq等信息。很神奇的样子。我对这个有点兴趣,再加上我最近想学node,于是前天晚上开始从nodejs.org的主页hello,word开始学起。用了半天写出了这个简单的神奇图片 制作服务器。
首先是名词解释,允许我用度娘的链接HTTP_REFFER
通过referer的名词解释可以知道访问外部图片的时候会带上此次浏览的信息,那我们就去看看qq空间的referer信息有哪些?
我在这里用的IE的开发者工具分析,大多数浏览器都有这个功能。
从这幅图中的REFERER可以看到我个人的qq号。于是我就想把这个图片链接到我个人图片服务器不就行了吗。
http.createServer(function (request, response) {
fs.readFile('default.png', 'binary', function (err, file) {
response.writeHead(200, {'Content-Type': 'image/png'});
response.write(file, 'binary');
response.end();
});
}).listen(8080, '127.0.0.1');
这是最简单的读取本地图片并显示的服务器代码。
下面开始增加对refer的判断。我通过http检测工具知道,只有在qq空间的个人中心才能获取到此人的qq号,而在其他位置,如:日志正文,手机qq等页面都是没有此referer的,所以此神奇图片只能在个人中心浏览之后,再加上缓存才能在pc端的其他页面看到。
代码如下:
var http = require('http');
var url = require('url');
var fs = require('fs');
http.createServer(function (request, response) {
// 如果没有referer就算显示默认图片
if (!request.headers.referer) {
return showDefaultPng();
}
// referer不是从个人中心过来的也显示默认图片
var aQQ = url.parse(request.headers.referer).pathname.match(/\d+/);
if(aQQ===null) {
return showDefaultPng();
}
// 从腾讯的接口获取qq号对应的个人信息
http.get('http://base.qzone.qq.com/fcg-bin/cgi_get_portrait.fcg?uins=' + aQQ[0], function (res) {
var infoBuffer = [];
res.on('data', function (data) {
infoBuffer.push(data);
});
res.on('end', function () {
var sInfo = Buffer.concat(infoBuffer);
var aInfo = sInfo.toString().replace(/"/g, "").match(/\[(.+)\]/);
if (!aInfo) {
// 如果不能获取到个人信息,依然显示默认图片
return showDefaultPng();
}
else {
// 如果能正确获取信息,就需要从qq图片服务器拉取头像
var a = aInfo[1].split(',')[0];
var req = http.request({'hostname': url.parse(a).hostname, 'method': 'get', 'port': '80', 'path': url.parse(a).pathname}, function (res) {
var data = [];
res.on('data', function (chunk) {
data.push(chunk);
});
res.on('end', function () {
var buffer = Buffer.concat(data);
// 增加缓存,并发送出去
response.writeHead(200, {'Content-Type': 'image/png',
'Cache-Control': 'public,max-age=31536000'
});
response.write(buffer, 'binary');
response.end();
});
});
req.end();
}
});
});
function showDefaultPng() {
fs.readFile('default.png', 'binary', function (err, file) {
response.writeHead(200, {'Content-Type': 'image/png'});
response.write(file, 'binary');
response.end();
});
}
}).listen(8080, ‘127.0.0.1’);
console.log(‘Server running at http://127.0.0.1:8080/’);
http://base.qzone.qq.com/fcg-bin/cgi_get_portrait.fcg?uins=你的qq号 这个链接可以查询到你的qq的基本信息。
ps: 我有两年的JS经验,两年的JAVA经验,搭过express和mongo的个人博客经验,所以也不能说是完全的node新手。
Node.js 实现 QQ 空间“神奇图片”的制作原理
相信很多人都看到过 QQ 空间中转发的日志里有一张神奇图片,这张图片会显示你的头像、个人 QQ 等信息。这个功能看起来非常神奇。我对这个功能很感兴趣,加上最近想学习 Node.js,于是我在半天内编写了一个简单的神奇图片生成服务器。
名词解释
首先,我们来了解一下 HTTP_REFERER 这个名词。简单来说,当浏览器请求一个外部资源时,它会带上这次请求的一些信息,包括来源地址(即 HTTP_REFERER)。我们可以利用这个特性来识别用户是从哪个页面跳转过来的。
分析 QQ 空间的 REFERER 信息
为了了解 QQ 空间的 REFERER 信息,我使用了 IE 的开发者工具进行分析。大多数现代浏览器都提供了类似的工具。以下是我分析的结果:
从上图中可以看到,我的 QQ 号码作为 REFERER 信息的一部分被传递。因此,如果我们要实现类似的功能,只需要将图片链接到我们的图片服务器即可。
最简单的实现
首先,我们来实现一个最简单的读取本地图片并显示的服务器代码:
const http = require('http');
const fs = require('fs');
http.createServer((request, response) => {
fs.readFile('default.png', 'binary', (err, file) => {
response.writeHead(200, {'Content-Type': 'image/png'});
response.write(file, 'binary');
response.end();
});
}).listen(8080, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8080/');
这段代码创建了一个 HTTP 服务器,监听 8080 端口,并读取 default.png
文件返回给客户端。
增加对 REFERER 的判断
接下来,我们需要增加对 REFERER 的判断逻辑。只有在 QQ 空间的个人中心页面访问时,才会获取用户的 QQ 号码,并根据 QQ 号码从腾讯的接口获取用户信息,再从 QQ 图片服务器拉取头像。
const http = require('http');
const url = require('url');
const fs = require('fs');
http.createServer((request, response) => {
// 如果没有 REFERER 信息,直接显示默认图片
if (!request.headers.referer) {
return showDefaultPng();
}
// 解析 REFERER 中的 QQ 号码
const aQQ = url.parse(request.headers.referer).pathname.match(/\d+/);
if (!aQQ) {
return showDefaultPng();
}
// 从腾讯的接口获取 QQ 号码对应的个人信息
http.get(`http://base.qzone.qq.com/fcg-bin/cgi_get_portrait.fcg?uins=${aQQ[0]}`, (res) => {
let infoBuffer = [];
res.on('data', (data) => {
infoBuffer.push(data);
});
res.on('end', () => {
const sInfo = Buffer.concat(infoBuffer);
const aInfo = sInfo.toString().replace(/"/g, "").match(/\[(.+)\]/);
if (!aInfo) {
// 如果无法获取到个人信息,依然显示默认图片
return showDefaultPng();
}
// 获取头像 URL 并读取头像
const a = aInfo[1].split(',')[0];
http.get(a, (res) => {
let data = [];
res.on('data', (chunk) => {
data.push(chunk);
});
res.on('end', () => {
const buffer = Buffer.concat(data);
// 设置缓存并发送图片
response.writeHead(200, {
'Content-Type': 'image/png',
'Cache-Control': 'public,max-age=31536000'
});
response.write(buffer, 'binary');
response.end();
});
});
});
});
function showDefaultPng() {
fs.readFile('default.png', 'binary', (err, file) => {
response.writeHead(200, {'Content-Type': 'image/png'});
response.write(file, 'binary');
response.end();
});
}
}).listen(8080, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8080/');
这段代码增加了对 REFERER 的判断逻辑。只有在 QQ 空间的个人中心页面访问时,才会从腾讯的接口获取用户信息,并根据 QQ 号码从 QQ 图片服务器拉取头像。如果无法获取到相关信息,则显示默认图片。
总结
通过以上代码,我们实现了 QQ 空间的神奇图片效果。该效果利用了 HTTP_REFERER 特性来识别用户来源,并根据 QQ 号码从腾讯的接口获取用户信息,从而实现动态展示用户头像等功能。
要在Node.js中实现一个模拟QQ空间“神奇图片”的服务,我们需要解析请求中的Referer
头来判断是否是从QQ空间的个人中心页面来的请求。如果是,则根据Referer
中的信息(例如用户的QQ号)从腾讯的接口获取用户头像,否则返回默认图片。
以下是实现这一功能的代码示例:
const http = require('http');
const url = require('url');
const fs = require('fs');
http.createServer((req, res) => {
// 如果没有Referer信息或者Referer不是来自QQ空间个人中心页面,则显示默认图片
if (!req.headers.referer || !/space\.qq\.com/.test(req.headers.referer)) {
return showDefaultPng(res);
}
const match = req.headers.referer.match(/uin=(\d+)/);
if (!match) {
return showDefaultPng(res);
}
const qqNumber = match[1];
// 从腾讯接口获取用户的头像URL
http.get(`http://base.qzone.qq.com/fcg-bin/cgi_get_portrait.fcg?uins=${qqNumber}`, (portraitRes) => {
let data = '';
portraitRes.on('data', (chunk) => {
data += chunk;
});
portraitRes.on('end', () => {
const portraitUrl = data.match(/"(\S+)"/)[1];
if (!portraitUrl) {
return showDefaultPng(res);
}
// 请求用户的头像
http.get(portraitUrl, (avatarRes) => {
res.writeHead(200, {'Content-Type': 'image/png'});
avatarRes.pipe(res);
}).on('error', () => {
showDefaultPng(res);
});
});
}).on('error', () => {
showDefaultPng(res);
});
function showDefaultPng(res) {
fs.readFile('default.png', 'binary', (err, file) => {
if (err) {
res.writeHead(500);
res.end('Internal Server Error');
return;
}
res.writeHead(200, {'Content-Type': 'image/png'});
res.write(file, 'binary');
res.end();
});
}
}).listen(8080, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8080/');
在这个例子中:
- 首先检查
Referer
是否存在以及是否来自QQ空间个人中心页面。 - 如果是,从腾讯的接口获取用户头像的URL。
- 请求该URL获取头像并返回给客户端。
- 如果无法获取头像信息,则返回默认图片。
请注意,这个示例中的代码未考虑安全性问题,实际应用时需要增加相应的安全措施。