304
last-modified etag服务端设置 if-modified-since if-none-match 客户端 expires cache-control 200 强制缓存
gzip
accept-encoding 浏览器来的头
content-encoding 服务端设置
referrer referer
referer浏览器默认的
代表的资源的来源 (可以做安全判断) 可以在服务端用当前资源的host 和 referer 做对比如果不一致 说明这个资源就被其他网址所引用
如果你就想用别人 你可以把图片爬取下来,在去使用
/usr/hosts C:\Windows\System32\drivers\etc
const http = require('http');
const path = require('path');
const fs = require('fs');
const url = require('url');
const whiteList = ['a.zf.cn:3000'] //白名单
const server = http.createServer((req,res)=>{
const {pathname} = url.parse(req.url,true);
const absPath = path.join(__dirname,pathname);
fs.stat(absPath,function (err,statObj) {
if(err){
res.statusCode = 404;
res.end('Not Found');
return
}
if(statObj.isFile()){
// 只有别人引用这张图片才有referer 直接打开是没有referer
if(/(\.png)|(\.jpg)/.test(absPath)){
let referer = req.headers['referer'] || req.headers['referrer'];
if(referer){ // 说明这个资源被引用了
let hostname = req.headers.host;
referer = url.parse(referer).host;
console.log(hostname,referer)
if(hostname !== referer && !whiteList.includes(referer)){
let errorFile = path.join(__dirname,'2.jpg')
fs.createReadStream(errorFile).pipe(res);
return
}
}
}
fs.createReadStream(absPath).pipe(res);
}else{
res.statusCode = 404;
res.end('Not Found');
}
})
});
server.listen(3000);
- 什么情况referer会改变?
服务端可以自己发一个请求,自己伪造一个referer,前端改不了。
const http = require('http');
const fs = require('fs');
http.get({
hostname:'a.zf.cn',
port:3000,
path:'/1.jpg',
headers:{
referer:'b.zf1.cn' //伪造referer
}
},function (res) {
res.pipe(fs.createWriteStream('test.jpg'))
});
// superagent
// Puppeteer
多语言 目前来说都是前端多语言 i18n
1.前端实现多语言vue-i18n 2.通过路径来实现多语言/zh/en 3.通过请求来实现多语音 (header)// Accept-Language: zh-CN,zh;q=0.9
const http = require('http');
const path = require('path');
const fs = require('fs');
const url = require('url');
let languages = {
en: {
message: {
hello: 'hello world'
}
},
ja: {
message: {
hello: 'こんにちは、世界'
}
},
"zh-CN": {
message: {
hello: '你好'
}
}
}
const server = http.createServer((req, res) => {
const {
pathname
} = url.parse(req.url, true);
const absPath = path.join(__dirname, pathname);
// 如果访问服务器 我需要根据header 返回不同的内容
// Accept-Language: ja,en;q=0.8,zh;q=0.9 [{name:'ja',q:1},{name:'zh-CN1',q:1},{name:'zh-CN1',q:1}]
let lans = req.headers['accept-language'];
if(lans){
let r = lans.split(',').map(lan=>{
let [name,q] = lan.split(';');
let obj = {}
obj.name = name;
if(!q){ // q是权重,默认1
q = 'q=1';
}
obj.q = q.split('=')[1];
return obj;
}).sort((a,b)=>b.q - a.q);
res.setHeader('Content-Type','text/plain;charset=utf-8')
for(let i = 0; i < r.length;i++){
let lan = languages[r[i].name];
if(lan && lan.message){
return res.end(lan.message.hello);
}
}
}
return res.end('not has language');
});
server.listen(3000);
断点续传 206
-
前端需要记录一个 上传的位置 (需要维护一个上传的位置)
举例:curl --header range:bytes=0-3 -V http://www. baidu.com
curl命令行工具,发出网络请求,获取网络数据,看到网页源代码
range:bytes=0-3 分段请求字节数,从0字节开始,0-3,4个字节
206 : 如果服务器能够正常响应的话,服务器会返回 206 Partial Content 的状态码
// range:bytes=4-7 客户端的
// Content-Range: bytes 4-7/2381 ,2381代表文件总大小 (服务端的)
// 206 实现断点续传
// 上传 可以暂停
// 前端需要记录一个 上传的位置 (需要维护一个上传的位置)
// range:bytes=4-7 客户端的
// Content-Range: bytes 4-7/2381 文件总大小
// curl --header range:bytes=0-3 -V http://www. baidu.com
const http = require('http');
const path = require('path');
const fs = require('fs');
const url = require('url');
const whiteList = ['a.zf.cn:3000'];
const file = fs.statSync(path.resolve(__dirname, '1.txt'));
const pathUrl = path.resolve(__dirname, '1.txt')
const size = file.size; //文件的总大小
const server = http.createServer((req, res) => {
const {
pathname
} = url.parse(req.url, true);
const range = req.headers['range']; //取浏览器的range
if (range) {
let matches = range.match(/(\d*)-(\d*)/); //取range的字节范围
let [, start = 0, end] = matches //,全部,start默认0,end默认默认全部就是总大小size
end = end == '' ? size : end;
res.statusCode = 206;
res.setHeader('Content-Range', `bytes ${start}-${end}/${size}`);
console.log(start, end, size)
fs.createReadStream(pathUrl, {
start: Number(start),
end: Number(end)
}).pipe(res)
} else {
fs.createReadStream(pathUrl).pipe(res)//读整个文件,没有范围就全部
}
});
// 实现下载
server.listen(3000);
-
前端分片 续传
// 每次客户请求服务器 都返回部分内容 const http = require('http'); const fs = require('fs'); // 续传 分片上传每次下载前端记载位置 let start = 0; function download(){ let end = start + 5 http.get({ host:'localhost', port:3000, method:'get', headers:{ Range:`bytes=${start}-${end-1}` } },function (res) { // xxx-xxx/total 迅雷 let total = res.headers['content-range'].split('/')[1]; //总大小 res.on('data',function (data) {//监听数据到来 fs.appendFileSync('2.txt',data);//把数据写到2.txt if(total > end){//判断别死循环 setTimeout(() => { start += 5; download(); //递归调用 }, 1000); } }) }) } download();
正向代理和反向代理
- 如果代理服务器是帮助客户端的 就是正向代理vpn
- 帮助服务器的就是反向代理nginx
- webpack proxy 我发了一个请求 webpack
- cdn 正向代理
正向代理 可以在请求的时候增加一些自定义属性 权限认证 ,跳板机 nginx 反向代理,作用做缓存
虚拟主机 是反向代理 ecs 服务 一个服务可以部署多个项目 多个域名 http-proxy a.zf.cn -> 网站 b.zf.cn -> 网站
80服务器 => 3000 => 4000
反向代理比较多。80服务器是反向的,做分发用的。
http-prox:npmjs.com/package/htt…
//80.js
const http = require('http');
const httpProxy = require('http-proxy');// 代理服务,分发
const proxy = httpProxy.createProxyServer();//http://npmjs.com/package/http-proxy
http.createServer((req,res)=>{
let host = req.headers.host;
let obj = {
'a.zf.cn':'http://localhost:3000',
'b.zf.cn':'http://localhost:4000',
}
// 增加权限判断 过滤操作
proxy.web(req,res,{
headers:{
a:1
},
target:obj[host]
})
}).listen(80);
// nginx 配置不同的域名 跳到不同的项目
// webpack 我们访问服务器 代理服务器会拦截用户请求 -->转发给服务器
//3000.js
const http = require('http');
http.createServer((req,res)=>{
res.end('3000' + req.headers.a)
}).listen(3000);
//4000.js
const http = require('http');
http.createServer((req,res)=>{
res.end('4000')
}).listen(4000);
//302.js
const http = require('http');
http.createServer((req,res)=>{
// 判断当前用户是移动端还是pc端
let userAgent = req.headers["user-agent"]; // 判断用户内核
res.statusCode = 302;
if(userAgent.includes('iPhone')){
res.setHeader('Location','http://www.baidu.com');
}else {
res.setHeader('Location','http://www.zfpx.cn');
}
res.end();
}).listen(3000);
header 使用场景 和 每个header的意义
HTTP常见Header
Content-Type: 数据类型(text/html等),显示方式
Content-Length: Body的长度
Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
User-Agent: 声明用户的操作系统和浏览器版本信息;
referer: 当前页面是从哪个页面跳转过来的;
location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问,后面加上location
Cookie: 用于在客户端存储少量信息,保存以前的客户端登录信息。保存在服务器端(set-cookie),保存在客户端(cookie)
cache-control:缓存寿命
transfer-Encoding: chunked,以模块形式传输,如果存在此属性可以不写Content-Length