# 十六.action

# 1.防盗链

  • 从一个网站跳转,或者网页引用到某个资源文件时,HTTP 请求中带有 Referer 表示来源网页的 URL
  • 通过检查请求头中的 Referer 来判断来源网页的域名
  • 如果来源域名不在白名单内,则返回错误提示
  • 用浏览器直接访问图片地址是没有 referer 的
let http = require("http");
let url = require("url");
let path = require("path");
let fs = require("fs");
let util = require("util");
let stat = util.promisify(fs.stat);
let mime=require('mime')

let server = http.createServer(function(req, res) {
  let { pathname } = url.parse(req.url);
  //拼接真实文件路径
  let realPath = path.join(__dirname, pathname);
try{
let statObj=await stat(realPath)
//是文件 返回文件
if(statObj.isFile()){
//类型库mime
res.setHeader('Content-Type',mime.getType(ealPaht)+';charset=utf8')
    fs.createReadStream(realPath).pipe(res)


}else{
//目录找html
    let url=path.join(realPath,'index/html')
    res.setHeader('Content-Type','text/html;charset=utf8')
    fs.createReadStream(url).pipe(res)
}
}catch(e){
    res.statusCode=404
    res.end('Not found')
}






//   fs.stat(realPath, function(err, statObj) {
//     if (err) {
//       res.statusCode = 404;
//       res.end("Not found");
//     } else {
//       if (statObj.isFile()) {
//         res.setHeader("Content-Type", "text/html;charset=utf8");
//         fs.createReadStream(realPath).pipe(res);
//       } else {
//         let url = path.join(realPath, "index.html");
//         fs.createReadStream(realPath).pipe(res);
//       }
//     }
//   });
});
server.listen(3000, function() {
  console.log("3000");
});

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>

  <body>
    hello 你好
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13

# 2.多语言

可以通过 Accept-Language 检测浏览器的语言

  • 请求头格式 Accept-Language: Accept-Language:zh-CN,zh;q=0.9
  • 响应头格式 Content-Language:zh-CN
let http = require("http")
let url = require("url")
let path = require("path")
let fs = require("fs")
let obj = {
  zh: {
    data: "你好",
  },
  en: {
    data: "hello",
  },
  ja: {
    data: "1234",
  },
}
let defaultLanguage = "en"
let server = http.createServer(async function(req, res) {
  let lan = req.headers["accept-language"]
  res.setHeader("Content-Type", "text/plain;charset=utf8")
  if (lan) {
    let lans = lan
      .split(",")
      .map((l) => {
        let [name, q = 1] = l.split(";")
        return {
          name,
          q: q === 1 ? 1 : Number(q.split("=")[1]),
        }
      })
      .sort((a, b) => b.q - a.q)
    for (let i = 0; i < lans.length; i++) {
      let lanName = lans[i].name
      if (obj[lanName]) {
        res.end(pobj[lanName].data)
      }
    }
    console.log(lans)
  } else {
    res.setHeader("Content-Type", "text/plain;charset=utf8")
    res.end(obj[defaultLanguage].data)
  }
})
server.listen(3000, function() {
  console.log(3000 + "连接成功")
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 3.缓存

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>

  <body>
    缓存
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
//304走浏览器的缓存
//缓存的类型 有两种 强制缓存 + 对比缓存
let http = require("http")
//页面 可能内部引用一个css 我希望css缓存

let url = require("url") // pathname,query
let path = require("path")
let fs = require("fs")
let util = require("util")
let stat = util.promisify(fs.stat)
let mime = require("mime")
let crypto = require("crypto")
let server = http.createServer(async function(req, res) {
  console.log(req.url)
  //告诉浏览器十秒内不要找我
  res.setHeader("Cache-Control", "no-cache")
  res.setHeader("Exipres", new Date(Date.now() + 10 * 1000).toLocaleString())

  //第一次访问的时候, 要给浏览器加一个头last-modified
  //第二次请求的时候,会自动带一个头 if-modify
  //如果当前带过来的头和文件当前的状态有出入,说明文件

  //第一次来访问 给你一个文件的签名 Etag :各种
  //下次你再来访问 会带上这个标签 if-none-match
  //我在去拿文件当前的内容 在生成一个标签 如果相等 返回304

  let { pathname } = url.parse(req.url)
  let realPath = path.join(__dirname, pathname) // 拼接真实文件的路径
  try {
    let statObj = await stat(realPath) // 判断文件是否存在
    if (statObj.isFile()) {
      res.setHeader("Etag")
      crypto.createHash("md5")
      let prev = req.headers["if-modified-since"]
      let current = statObj.citime.toGMTString()
      if (prev === current) {
        res.statusCode = 304
        res.end()
      }
      // 是文件 返回文件
      res.setHeader("Content-Type", mime.getType(realPath) + ";charset=utf-8")
      fs.createReadStream(realPath).pipe(res)
    } else {
      res.setHeader("Last-Modified", statObj.ctime.toGMTString())
      let url = path.join(realPath, "index.html") // 目录找html
      res.setHeader("Content-Type", "text/html;charset=utf-8")
      fs.createReadStream(url).pipe(res)
    }
  } catch (e) {
    // 不存在返回404
    res.statusCode = 404
    res.end("Not found")
  }
})

server.listen(3000, function() {
  console.log(`server start 3000`)
})

//第一次来先来个强制缓存Cache-Control + expires
//过了10s再刷新 此时会再次发送请求 启用对比缓存
// 1) Last-Modified:ctime 2)if-modified-since
//1) Etag 2)if-none-match
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//crypto 加密 md5(摘要算法)
//md5的特点 不可逆
//不同的内容加密长度是一样的
//如果内容不相同 那么摘要的结果肯定也是不同的
let crypto = require("crypto")
let r = crypto
  .createHash("md5")
  .update("123456")
  .digest("base64")
console.log(r)

//加盐算法
//弄一个密码 根据我的密码进行加密 加密cookie
let fs = requier("fs")
let s = fs.readFileSync()
let r2 = crypto
  .createHmac("sha1", s)
  .update("123456")
  .digest("hex")
console.log(r2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 4. 代理服务器

代理(英语:Proxy),也称网络代理,是一种特殊的网络服务,允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。一些网关、路由器等网络设备具备网络代理功能。一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击。

npm install http-proxy --save
1
  • web 代理普通的 HTTP 请求
  • listen port
  • close 关闭内置的服务

https://www.npmjs.com/package/http-proxy (opens new window)

let httpProxy = require("http-proxy")
let http = require("http")
let proxy = httpProxy.createProxyServer()

http
  .createServer(function(req, res) {
    proxy.web(req, res, {
      target: "http://localhost:8000",
    })
    proxy.on("error", function(err) {
      console.log("出错了")
      res.end(err.toString())
    })
  })
  .listen(8080)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 5. 虚拟主机

通过 Host 实现多个网站共用一个端口,多个网站共用一个服务器

let http = require("http")
let httpProxy = require("http-proxy")
let proxy = httpProxy.createProxyServer()

let hosts = {
  "a.zfpx.cn": "http://localhost:8000",
  "b.zfpx.cn": "http://localhost:9000",
}
let server = http
  .createServer(function(req, res) {
    let host = req.headers["host"]
    host = host.split(":")[0]
    let target = hosts[host]
    proxy.web(req, res, {
      target,
    })
  })
  .listen(80)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18