作为一名专业的切图工程师,我从来不care网页的header,最多关心Status Code是不是200。但是HEADER真的很重要啊,客户端从服务器端获取内容,首先就是通过HEADER进行各种沟通!HEADER可以帮助我们完成许多骚操作,提高网站的性能,用户的体验。好了让我们来feel一下。

初级骚操作

  • 多语言(Accept-Language
  • 防盗链(RefererReferered
  • gzip,简单地说就是省流量(Accept-EncodingContent-Encoding

多语言

多语言就是一个网站可以实现多种语言的切换,这里不讨论建N个网站,一个语言对应一个网站。这里讨论如何智能返回用户所需的语言。

server client
向server扔过去了Accept-Language
接收对方的Accept-Language
字段大概这样子zh,en-US;q=0.9,en;q=0.8
开始处理,将字段变成带权重q的数组
排序好大概长这样[{"name":"zh","q":1},{"name":"en-US","q":0.9},{"name":"en","q":0.8}]
根据权重返回拥有的语言,有zh返回zh,没有zh就返回en-US
万一我没有对方需要的语言包,怎么办?急,在线等!
没办法了,只能给对方我们的官方(默认)语言
发送,请接收
您的ACCEPT语言已匹配 这个网站挺上道的,虽然是国外网站,但知道我是中文
我们没有你所在地区的语言包 emmmm,这是火星文吗?

附赠多语言的简易实现版:

let languages = {zh:{title:"你好",content:"同学"},en:{title:"Hey",content:"guy"},
}
//设置默认语言,万一用户的语言我们不支持呢?
let defaultLanguage="zh"
let http = require('http');
function getLanguage(client_langs){let finalLanguage=defaultLanguagetry{if(client_langs){//排序获取语言顺序client_langs=client_langs.split(',').map(l=>{let [name,q] = l.split(';');q = q?Number(q.split('=')[1]):1 return {name,q}}).sort((a,b)=>b.q-a.q);//匹配服务器有的语言,并返回for(let i = 0 ;i <languages.length;i++){let name= languages[i].name;if(languages[name]){finalLanguage=name;break;}}}}catch(e){}return languages[finalLanguage]
}
http.createServer(function (req,res) {//获取客户端的语言let client_langs = req.headers['Accept-Language'];let lan=getLanguage(client_langs)//将语言打印到客户端res.end(`<p>${lan.title}</p><p>${lan.content}</p>`)
}).listen(3000);

防盗链

这个技术用的最多的应该就是对于图片的限制,只有本域名可以获取到,其他域名想都不要想。

server client
在某网站上请求了一张图片
通过RefererReferered发现此网站域名不在我方白名单内
此图片不提供给某网站
此时po上了一张万用土
支持正版请上我们网站

实现原理,此处我用iframe来做例子,其实原理很简单就是对比来源,要么和请求资源一致要么在白名单内,不然就拒绝。当然如果没有来源的情况下就直接放行,万一人家是单独打开的呢,不是盗链:

let http =  require('http');
let fs = require('fs');
let url = require('url');
let path = require('path');
// 设置白名单
let whiteList = ['localhost:3000'];
http.createServer(function (req,res) {//获取请求地址let { pathname } = url.parse(req.url);// 获取物理地址let realPath = path.join(__dirname,pathname);// 获取文件状态fs.stat(realPath,function(err,statObj) {if(err){res.statusCode = 404;res.end();}else{// 重点来了let Referer = req.headers['Referer'] || req.headers['referred'];//如果有来源if(Referer){//获取双方域名let current = req.headers['host'] Referer = url.parse(Referer).hostconsole.log(current,Referer)//如果域名相同活在白名单中,放行!if (current === Referer || whiteList.includes(Referer)){fs.createReadStream(realPath).pipe(res);}else{//不放行,此乃盗链!给你个眼神自行体会fs.createReadStream(path.join(__dirname,'files/2.html')).pipe(res);}}else{//没有来源,也放行。万一是单独打开的呢~fs.createReadStream(realPath).pipe(res);}}})
}).listen(3000);

gzip

现代浏览器很高级,已经可以接受压缩包了。佩服佩服。那么该如何传输压缩的网页呢?

server client
向server扔过去了Accept-Encoding
大概结构是这样的gzip, deflate, br
get到了对方的用意,开始配置压缩
如果支持压缩,先设置个头部Content-Encoding
有很多种压缩方式,按照server优先支持的匹配
在线压缩网页,成功后返回client
欢欢喜喜省了流量,而且不影响体验

附赠建议代码,大家测试的时候,别忘了创建测试的html文件

let http = require('http');
//用于压缩文件所需的库
let fs = require('fs');
let path = require('path');
//压缩的库
let zlib = require('zlib');
http.createServer(function (req,res) {//获取客户端接受的压缩方式let rule = req.headers['Accept-Encoding'];// 创建原文件可读流let originStream=fs.createReadStream(path.join(__dirname, '1.html'));if(rule){// 啊啊啊!正则是个坎,我怕我是跨不过去了。if(rule.match(/\bgzip\b/)){//如果支持压缩!一定要设置头部!res.setHeader('Content-Encoding','gzip');originStream=originStream.pipe(zlib.createGzip())} else if (rule.match(/\bdeflate\b/)){res.setHeader('Content-Encoding', 'deflate');originStream=originStream.pipe(zlib.createDeflate())}}// 输出处理后的可读流originStream.pipe(res)
}).listen(3000);

中级操作

初级操作大多只需要靠***配置HEADER即可以实现***,中级我们当然要难一点,大多需要client和server打配合。

  • client给server发送内容(Content-TypeContent-Length)
  • client从server获取内容(RangeContent-Range)
  • client爬虫,抓取网页

client给server发送内容

server client
给你了一串数据,你给处理下
没头没脑,谁知道你要做什么,请设置好HEADER
好吧,告诉你Content-TypeContent-Length
可以可以,数据的内容类型是长度是很必要的
把数据传给你了,你看一下
收到~监听收到的数据是一组Buffer
接受完毕,合并Buffer
根据Content-Type对数据进行处理
格式化数据,end

Server代码

let http = require('http');
let server = http.createServer();
let arr=[]
server.on('request', (req, res)=>{req.on('data',function (data) {//把获取到的Buffer数据都放入熟组arr.push(data);});req.on('end',function() {// 请求结束了,好了可以开始处理断断续续收到的Buffer了// 合并bufferlet r = Buffer.concat(arr).toString();if (req.headers['content-type'] === 'x-www-form-urlencoded'){let querystring = require('querystring');r = querystring.parse(r); // a=1&b=2然后格式化console.log("querystring",r);} else if (req.headers['content-type'] === 'application/json'){//听说是JSON格式的console.log("json",JSON.parse(r));} else{//没有格式?那原来是啥就是啥吧。console.log("no type",r);}arr=[]res.end('结束了!');});
})
server.listen(3000,()=>{console.log(`server start`);
});

Client代码

// 设置请求地址的配置
let opts = {host:'localhost',port:3000,path:'/',// 头部设置很重要,头部设置很重要,头部设置很重要headers:{'Content-Type':'x-www-form-urlencoded',//长度超过3就没有人理你了"Content-Length":7}
}
let http = require('http');
let client = http.request(opts,function (res) {res.on('data',function (data) {console.log(data);})
});
client.end("a=1&b=2");

client从server获取部分内容

server client
我想要资源的部分内容
可以啊,告诉我范围
我放在HEADER中的Range了,bytes=0-3
Content-Range:bytes 0-3/7,请接受,此文件一共8字节,前3字节已经给你了 好的,那么把接下来的给我吧,bytes=4-7
给你给你都给你 end

大家都发现了吧,这样的range获取数据,完全是断点续传的简陋版啊!不过这边有一个点容易犯错就是文件大小的计算,因为文件字节的位置是按照0开始算,所以range的全范围都是0~size-1/size-1,大家注意下。

server 端

let http = require('http');
let fs = require('fs');
let path = require('path');
// 当前要下载的文件的大小
let size = fs.statSync(path.join(__dirname, 'my.txt')).size;
let server = http.createServer(function (req, res) {let range = req.headers['range']; //获取client请求访问的部分内容if (range) {let [, start, end] = range.match(/(\d*)-(\d*)/);start = start ? Number(start) : 0;end = end ? Number(end) : size - 1; // 10个字节 size 10  (0-9)console.log(`bytes ${start}-${end}/${size - 1}`)res.setHeader('Content-Range', `bytes ${start}-${end}/${size - 1}`);fs.createReadStream(path.join(__dirname, 'my.txt'), { start, end }).pipe(res);} else {// 会把文件的内容写给客户端fs.createReadStream(path.join(__dirname, 'my.txt')).pipe(res);}
});
server.listen(3000);

client端

let opts = {host:'localhost',port:3000,headers:{}}
let http = require('http');
let start = 0;
let fs = require('fs');
function download() {//分流下载,部分下载opts.headers.Range = `bytes=${start}-${start+3}`;start+=4;let client = http.request(opts,function (res) {let total = res.headers['content-range'].split('/')[1];res.on('data',function (data) {fs.appendFileSync('./download.txt',data);});res.on('end',function () {//结束之后,1s之后再下载setTimeout(() => {console.log(start,total)if (start <= total)download();}, 1000);})});client.end();
}
download()

client抓取网页内容,简易爬虫

这一块的操作其实很简单,只要建一个请求获取到网页就可以了。 难点在于:如何将有效的信息剥离网页,过滤掉无用信息。 我这里抓去了百度的娱乐版,百度还算良心,是utf8的,不然就要乱码了。

let http = require('http');
let opts = {host:'news.baidu.com',path:'/ent'
}
//创建一个请求,获取网站内容
let client = http.request(opts,function (r) {let arr= [];//资源不可能一次下载完成,因此每次获取到数据都要push到arr中r.on('data',function (data) {arr.push(data);});r.on('end',function() {//合并资源let result = Buffer.concat(arr).toString();//对资源进行处理,可以是变成我这样的对象,之后不管做什么处理都很方便let content = result.match(/<ul class="ulist mix-ulist">(?:[\s\S]*?)<\/ul>/img).toString().match(/<li>(?:[\s\S]*?)<\/li>/img);content=content.map((c)=>{let href=/<a href="(?:[\S]*?)"/img.exec(c)let title=/">(?:[\s\S]*?)<\/a>/img.exec(c)return {href:href[0].replace(/"/img,"").replace("<a href=",""),title:title[0].replace(/">/img,"").replace("</a>","")}})console.log(JSON.stringify(content))arr= [];})
});
client.end();

通过HTTP的HEADER完成各种骚操作相关推荐

  1. Git科普文,Git基本原理各种骚操作

    Git简单介绍 Git是一个分布式版本控制软件,最初由Linus Torvalds创作,于2005年以GPL发布.最初目的是为更好地管理Linux内核开发而设计.   Git工作流程以及各个区域 Wo ...

  2. DVWA 不跳转_利用url跳转漏洞冒充公安局官网的骚操作

    黑客的骚操作 各位大佬们晚上好.我今天又又又更新了. 刚刚发现了一个漏洞素材,在这里和大家分享一下漏洞以及被利用的用途,这个漏洞乍一看风险不大,实际上被有心人利用起来,非常的可怕,毕竟很少有人会怀疑警 ...

  3. 音视频骚操作,FFmpeg 如何播放带「图片」的 M3U8 视频,IJKPlyaer 适配非标 TS 文件

    如果看到一个需要播放的视频链接显示是一张图片,你会不会感觉有点懵?如果这张图片写着 png,然后实际格式是 bmp ,你会不会更懵了?如果这个 bmp 还做了加密篡改呢?今天我们要聊的就是这样一个充满 ...

  4. 闪电侠 Netty 小册里的骚操作

    前言 即使这是一本小册,但基于"不提笔不读书"的理念,仍然有必要总结一下.此小册对于那些"硬杠 Netty 源码 却不曾在千万级生产环境上使用实操"的用户非常有 ...

  5. 五分钟没有操作自动退出_这又是什么骚操作??5只蚂蚁战略配售基金拟增设B类份额,自动赎回退出!!...

    他来了,他来了,这又是什么骚操作??昨天,五只创新未来18个月封闭运作混合型证券投资基金发布联合声明,会为这个战略配售基金安排一个月的退出选择期. 5只创新未来18个月封闭运作混合型证券投资基金发布联 ...

  6. GitHub 骚操作,个人页还能这么玩?

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 之前写过一篇 GitHub 骚操作的文章 GitHub 竟 ...

  7. 杀疯了!通过游戏“元宇宙”,Deepmind让AI学会玩各种没玩过的游戏,骚操作不断...

    来源:大数据文摘本文约1800字,建议阅读7分钟 面对任务一看就会的AI,离我们心里的通用人工智能还有多远呢? 对于AI来说,完成一个单一任务或许相对简单,但是涉及到合作和博弈时,AI往往显得有些愚蠢 ...

  8. K项目的一些心得之全球模板里的几个骚操作

    K项目的一些心得之全球模板里的几个骚操作 1,数据迁移阶段,物料主数据分类视图里,batch class的代码跟物料号相同. 这意味着如果需要迁移的物料有1万个,导入程序会自动创建1万023类型的分类 ...

  9. git idea 可视化_那些你应该知道的,但是你一定不知道的 Git 骚操作

    Hello 大家好,作为团队中的主程阿粉经常参与很多核心功能的开发,而且很多时候一个需求没做好中间又插入新的紧急的需求或者 bug 修复,每次遇到这种情况,如果两个地方代码不冲突的话还好,可以直接在本 ...

最新文章

  1. Oracle-维护存在主键的分区表时的注意事项
  2. 收藏开发人员常去网站
  3. 查看was中项目类的加载顺序
  4. 07_QueueWithTwoStacks
  5. Python文件上传功能简单实现
  6. 快速排序伪代码_归并排序之入门到quot;放弃quot;
  7. Unreal Engine 4 的 光和影
  8. 替换Android中VM 加载动态库方式
  9. 解决MFC 窗口创建时 争夺焦点的问题
  10. Exponent CMS 2.3.9 配置文件写入 Getshell分析
  11. flashfxp修改服务器密码,flashfxp服务器端设置
  12. 拉卡拉支付最新支付方式预览——刷脸支付上线
  13. 【程序员读论文】题外篇:怎么读论文
  14. WebView加载淘宝,天猫链接失败
  15. python免费自学爬虫_看这里!免费python网络爬虫一站通
  16. vue3 composition API
  17. sklearn中shuffle的用法
  18. 最新版养猫小程序前端+后端搭建详细教程
  19. 【大数据】海量数据处理方法
  20. Django中遇到的问题以及解决方法

热门文章

  1. CProgressCtrl进度条控件实现进度滚动效果
  2. servlet (七)javaBean
  3. Hadoop介绍及最新稳定版Hadoop 2.4.1下载地址及单节点安装
  4. Linux之watch命令
  5. 中国移动虚拟服务器设置,在中国移动公众服务云平台上服务器虚拟化的设计与实现...
  6. js日期操作,某天的N天后,一个月后的日期
  7. zabbix分布式监控部署proxy安装
  8. 用user-selection实现让页面上的内容不能被选中
  9. 用js的document.write输出的广告无阻塞加载的方法(转)
  10. 关于企业应用SAP成本管理模式与方法的一些思考