IT即互联网技术,从事的工做和网络有很大的关系,前端要负责和后台(服务器)进行交互,其必然得通过网络,因此懂点网络知识有很大的帮助。html
- Cache-Control 控制缓存行为
- Connection 连接的管理
- Date 报文日期
- Pragma 报文指令
- Trailer 报文尾部的首部
- Trasfer-Encoding 指定报文主体的传输编码方式
- Upgrade 升级为其余协议
- Via 代理服务器信息
- Warning 错误通知
复制代码
- Accept 用户代理可处理的媒体类型
- Accept-Charset 优先的字符集
- Accept-Encoding 优先的编码
- Accept-Langulage 优先的语言
- Authorization Web 认证信息
- Expect 期待服务器的特定行为
- From 用户的电子邮箱地址
- Host 请求资源所在的服务器
- If-Match 比较实体标记
- If-Modified-Since 比较资源的更新时间,用于缓存
- If-None-Match 比较实体标记
- If-Range 资源未更新时发送实体Byte的范围请求
- If-Unmodified-Since 比较资源的更新时间(和If-Modified-Since相反)
- Max-Forwards 最大传输跳数
- Proxy-Authorization 代理服务器须要客户端认证
- Range 实体字节范围请求
- Referer 请求中的URI的原始获取方
- TE 传输编码的优先级
- User-Agent HTTP 客户端程序的信
复制代码
const http = require('http');
http.createServer(function (req,res) {
console.log(req.httpVersion)//打印请求行的协议版本号
console.log(req.url);//打印请求行的资源路径
console.log(req.method)//打印请求行方法
console.log(req.headers);//打印求头
//打印请求体,若是没有请求体不会触发data事件,通常用于POST、PUT等
req.on('data',function (data) {
console.log(data)
});
req.on('end',function (data) {//每次必定会触发'end'
console.log(data);
})
}).listen(3000);
复制代码
- Accept-Ranges 是否接受字节范围,用于206范围请求
- Age 资源的建立时间
- ETag 资源的匹配信息
- Location 客户端重定向至指定的URI
- Proxy-Authenticate 代理服务器对客户端的认证信息
- Retry-After 再次发送请求的时机
- Server 服务器的信息
- Vary 代理服务器缓存的管理信息
- www-Authenticate 服务器对客户端的认证
复制代码
- Allow 资源可支持的HTTP方法
- Content-Encoding 实体的编码方式
- Content-Language 实体的天然语言
- Content-Length 实体的内容大小(字节为单位)
- Content-Location 替代对应资源的URI
- Content-MD5 实体的报文摘要
- Content-Range 实体的位置范围
- Content-Type 实体主体的媒体类型
- Expires 实体过时时间,用于缓存
- Last-Modified 资源的最后修改时间,用于缓存
复制代码
//客户端请求:curl -v --header 'Range:bytes=0-3' localhost:4000
//download.txt => 1234567890\r\n1234567890\r\n1234567890\r\n
const http = require('http');
const fs = require('fs');
const size = fs.statSync('./download.txt').size;
http.createServer(function (req,res) {
let head = req.headers['range'];
if(head){
let [,start,end] = head.match(/(\d*)-(\d*)/);
start = start?Number(start):0;
end = end ? Number(end) : size-1;
console.log(start,end)
res.statusCode = 206;//状态码为206
res.setHeader('Accept-Ranges','bytes'); //服务器代表这是一个范围请求,范围请求的单位为字节
res.setHeader('Content-Length',end-start+1);//响应体的字节
res.setHeader('Content-Range', `bytes ${start}-${end}/${size}`)//响应体在响应报文中的位置
fs.createReadStream('./download.txt',{start,end}).pipe(res);
}else{
fs.createReadStream('./download.txt').pipe(res);
}
}).listen(4000);
复制代码
// Referer表示这个资源被哪一个网站引用了
// 若是当前请求的referer和当前服务器的域名不同表示图片被盗了
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const {promisify} = require('util');
const stat = promisify(fs.stat);
let whiteList = ['localhost']
http.createServer(async function (req, res) {
let { pathname } = url.parse(req.url);
let realPath = path.join(__dirname, 'static', pathname);
let s = await stat(realPath);
if(s.isDirectory()){
fs.createReadStream(path.join(realPath, '/index.html')).pipe(res);
}else{
let refer = req.headers['referer'] || req.headers['referred'];
if (refer){ // 当前引用的资源有没有refer
let host = req.headers.host.split(':')[0];
let r = url.parse(req.headers['referer']).hostname;
if (whiteList.includes(r) || r === host ){ //当前的请求网页host和主机名refer相同说明有访问权限
fs.createReadStream(realPath).pipe(res);
}else{ // 没有权限就返回裂图
fs.createReadStream(path.join(__dirname,'static/1.jpg')).pipe(res);
}
}else{
fs.createReadStream(realPath).pipe(res);
}
}
}).listen(5000);
复制代码
//客户端请求头:Accept-Language: en,zh;q=0.8,ja;q=0.9
const messages = {
en: 'hello world',
ja: 'こんにちは、世界',
zh: '你好世界',
}
let defaultEncoding = 'zh'
const http = require('http');
let server = http.createServer(function (req,res) {
let lan = req.headers['accept-language'];
if (lan){
//en,zh;q=0.8,ja;q=0.9 => [en, zh;q=0.8 ,ja;q=0.9]
//而且按照权重排序
let lans = lan.split(',').map(l=>{
let q = l.split(';')[1] ? Number(l.split(';')[1].split('=')[1]):1;
return {
name: l.split(';')[0],q
}
}).sort((a,b)=>b.q-a.q);
let l = null
for (let key in lans){
if (messages[lans[key].name]){
l = messages[lans[key].name];
break;
}
}
console.log(l);
if(l){
res.setHeader('Content-Type', 'text/html;charset=utf8;')
res.end(l);
}else{
res.setHeader('Content-Type', 'text/html;charset=utf8;')
res.end(messages[defaultEncoding]);
}
}else{
res.setHeader('Content-Type','text/html;charset=utf8;')
res.end(messages[defaultEncoding])
}
}).listen(5000);
复制代码
强制缓存+最后修改时间对比缓存:前端
const http = require('http');
const path = require('path');
const fs = require('fs');
const url = require('url');
const {promisify} = require('util');
const mime = require('mime');
const stat = promisify(fs.stat);
const static = path.join(__dirname,'static')
http.createServer(async function (req,res) {
let {pathname} = url.parse(req.url,true);
if(pathname === '/favicon.ico') return res.end();
let realPath = path.join(static,pathname);
let statObj = await stat(realPath);//请求的资源信息
//强制请求
res.setHeader('Cache-Control','no-cache'); // 10s内不会再次发起请求
let time = req.headers['if-modified-since'];// 浏览器再次到来时 会带上一个头 if-modified-since的字段
if(statObj.isFile()){
//对比缓存,把当前文件的最后修改时间发送告诉给客户端
res.setHeader('Last-Modified', statObj.ctime.toGMTString());
res.setHeader('Content-Type',mime.getType(realPath)+';chatset=utf8');
if (time === statObj.ctime.toGMTString()) { // 若是相等那就走缓存吧
res.statusCode = 304;
res.end();
}else{
fs.createReadStream(realPath).pipe(res);
}
}
}).listen(3000);
// 最后修改时间 通常会有些偏差 时间可能不会那么精确(一秒内改了屡次)
// CDN 分发的时间不一样 可能也会致使缓存失效
复制代码
强制缓存+关键字对比缓存:node
const http = require('http');
const path = require('path');
const fs = require('fs');
const url = require('url');
const {promisify} = require('util');
const mime = require('mime');
const stat = promisify(fs.stat);
const crypto = require('crypto');
cosnt static = path.join(__dirname,'static');
http.createServer(async function (req,res) {
let {pathname} = url.parse(req.url,true);
if(pathname === '/favicon.ico') return res.end();
let realPath = path.join(static,pathname);
let statObj = await stat(realPath);
//强制缓存
res.setHeader('Cache-Control','no-cache'); // 10s内不会再次发起请求
if(statObj.isFile()){
//对比缓存:Etag内容为请求资源通过MD5加密以后
let rs = fs.createReadStream(realPath);
let md5 = crypto.createHash('md5');
rs.on('data',function (data) {
md5.update(data);
});
rs.on('end',function () {
let r = md5.digest('base64');
res.setHeader('Etag',r );
if (req.headers['if-none-match'] === r ){
res.statusCode = 304;
res.end();
}else{
res.setHeader('Content-Type', mime.getType(realPath) + ';chatset=utf8');
fs.createReadStream(realPath).pipe(res);
}
})
}
}).listen(3000);
// 若是文件很是大,须要读取文件的内容比对,影响性能
复制代码
//获取浏览器支持的压缩方式Accept-Encoding: gzip, deflate, br
//压缩而且通知浏览器使用的压缩方式Content-Encoding: gzip
const http = require('http');
const fs = require('fs');
const zlib = require('zlib');
http.createServer(function (req,res) {
let encoding = req.headers['accept-encoding'];
if(encoding){
if (encoding.match(/\bgzip\b/)){
res.setHeader('Content-Encoding','gzip');
fs.createReadStream('./static/index.html').pipe(zlib.createGzip()).pipe(res);
} else if (encoding.match(/\bdeflate\b/)){
res.setHeader('Content-Encoding', 'deflate');
fs.createReadStream('./static/index.html').pipe(zlib.createDeflate()).pipe(res);
}else{
fs.createReadStream('./static/index.html').pipe(res);
}
}else{
fs.createReadStream('./static/index.html').pipe(res);
}
}).listen(3000);
复制代码
//
const http = require('http');
const server = http.createServer(function (req,res) {
if(req.url === '/visit'){
if(req.headers['cookie']){
res.setHeader('Content-Type', 'text/html;charset=utf-8');
let queryObj=require('querystring').parse(req.headers['cookie');
queryObj.visit++;
res.setHeader('Set-Cookie', `visit=${queryObj.visit}; httpOnly`);
res.end('你是第' + queryObj.visit+ '次访问')
}else{
res.setHeader('Content-Type','text/html;charset=utf8');
res.setHeader('Set-Cookie','visit=1; httpOnly');
res.end('你是第一次访问')
}
}
}).listen(6000);
复制代码
const http = require('http');
const uuid = require('uuid/v4');
const SESSION_ID = 'connet.sid'; // 卡号:110 = {m:1000}
cosnt session = {}
// csrf 加验证码 refer
let server = http.createServer(function (req, res) {
if (req.url === '/go') {
let cookies = require('querystring').parse(req.headers['cookie'],'; ','=');
if (cookies[SESSION_ID] && session[cookies[SESSION_ID]]) {
session[cookies[SESSION_ID]].m -= 200;
res.setHeader('Content-Type', 'text/html;charset=utf8');
res.end('你的卡有' + session[cookies[SESSION_ID]].m + '元');
} else {
let cardId = uuid();
session[cardId] = { m: 1000 };
res.setHeader('Set-Cookie', `${SESSION_ID}=${cardId}`);
res.setHeader('Content-Type', 'text/html;charset=utf8');
console.log(session)
res.end('你的卡有' + session[cardId].m + '元');
}
}
}).listen(8888);
复制代码
// www.self1.cn 代理 localhost:3001
// www.self2.cn 代理 localhost:3002
const map = {
'www.self1.cn': 'http://localhost:3001',
'www.self2.cn': 'http://localhost:3002',
}
const httpProxy = require('http-proxy');
const http = require('http');
const proxy = httpProxy.createProxyServer();
http.createServer(function (req, res) {
let head = req.headers['host'];
proxy.web(req, res, {
target: map[head]
});
}).listen(80);
复制代码
const http = require('http')
http.createServer(function (req, res) {
res.header("Access-Control-Allow-Origin", "*");//容许的域名( * 全部域)
res.header("Access-Control-Allow-Headers", "X-Requested-With");/服务器支持的头信息
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");//容许的方法
}).listen(9000, function () {
console.log('server is runing at 9000')
})
复制代码
IT即互联网技术,从事的工做和网络有很大的关系,前端要负责和后台(服务器)进行交互,其必然得通过网络,因此懂点网络知识有很大的帮助。接下来会介绍:web
本文参考:跨域