Accept-Language

Accept-Language通常用来实现多语言:

Accept-Language: <language>Accept-Language: *// Multiple types, weighted with the quality value syntax:Accept-Language: fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5

;q= (q-factor weighting) 示意优先程序,用绝对品质价值示意,又称为权重。

简略实现:

const http = require("http")const languages = {zh: "你好",en: "hello",jp: "こんにちは",}const server = http.createServer((req, res) => {  res.setHeader("Content-Type", "text/plain;charset=utf-8")  let lang = req.headers["accept-language"] // zh-CN,zh;q=0.9,en;q=0.8  if (!lang) return res.end("")  lang = lang    .split(",")    .filter((t) => t.includes(";"))    .map((t) => {      let [name, q] = t.split(";")      return {        name,        q: q.slice(2) * 1,      }    })    .sort((a, b) => a.q > b.q)  for (let i = 0; i < lang.length; i++) {    let work = languages[lang[i].name]    if (work) {      res.end(work)      break    }  }  res.end(JSON.stringify(lang))})server.listen(3000, () =>console.log(`Serving on: \r\n  http://localhost:3000`))

Accept-Ranges

HTTP申请范畴

HTTP 协定范畴申请容许服务器只发送 HTTP 音讯的一部分到客户端。范畴申请在传送大的媒体文件,或者与文件下载的断点续传性能搭配应用时十分有用。

范畴申请的响应状态:

  • 206 Partial Content 服务申请胜利
  • 416 Requested Range Not Satisfiable 申请范畴越界(范畴值超过了资源的大小)
  • 200 OK 不反对范畴申请返回整个资源,分段下载时,要先判断

Range 申请头:

Range: bytes=start-end

Range: bytes=10-:第10个字节及最初个字节的数据 Range: bytes=40-100:第40个字节到第100个字节之间的数据.

留神,这个示意[start,end],即是蕴含申请头的start及end字节的,所以,下一个申请,应该是上一个申请的[end+1, nextEnd]

Content-Range 响应头

// 服务器响应了前(0-10)个字节的数据,该资源一共有(3103)个字节大小。Content-Range: bytes 0-10/3103;// 服务器响应了11个字节的数据(0-10)Content-Length: 11;

代码实现

服务端按range范畴下载

const path = require("path")const http = require("http")const fs = require("fs")const DOWNLOAD_FILE = path.resolve(__dirname, "./server_download.txt")const TOTAL = fs.statSync(DOWNLOAD_FILE).size;http.createServer((req, res) => {  res.setHeader("Content-Type", "text/plain;charset=utf-8")  // curl http://www.example.com -i -H "Range: bytes=0-50"  const range = req.headers["range"]  // 没有range间接返回文件  if (!range) return fs.createReadStream(DOWNLOAD_FILE).pipe(res)  // 截取范畴值,还有种用,隔开的状况这里暂不思考  let [, start, end] = range.match(/(\d*)-(\d*)/)  start = start ? start * 1 : 0  end = end ? end * 1 : TOTAL  // 范畴申请胜利状态码 206 Partial Content  res.statusCode = 206  // 设置响应头  res.setHeader("Content-Range", `bytes ${start}-${end}/${TOTAL}`)  // 返回范畴数据  fs.createReadStream(DOWNLOAD_FILE, { start, end }).pipe(res)}).listen(3000, () => console.log(`Serving on 3000`))

客户端下载

const path = require("path")const http = require("http")const fs = require("fs")const DOWNLOAD_FILE = path.resolve(__dirname, "./client_download.txt")const ws = fs.createWriteStream(DOWNLOAD_FILE)let start = 0let mode = "start"  //下载模式 "start" | "pause"download()function download() {  const downloadConfig = {    hostname: "localhost",    port: 3000,    encoding: "utf-8",    headers: {      Range: `bytes=${start}-${start + 100}`,    },  }  const request = (res) => {    let total = res.headers["content-range"].split("/")[1] * 1    res.on("data", (chunk) => {      ws.write(chunk)      if (start <= total) {        start += 101        // 打印下载进度        console.clear();        console.log(`下载进度:${Math.min(parseInt((start / total) * 100), 100)}%\r\n按p键后回车可暂停`)        setTimeout(()=>{            // mode 是start模式 则持续下载            mode === "start" ? download() : console.log("暂停下载,按任意键回车后下载")        },1000)      } else {ws.end()}    })    res.on("end", () => {      if (total > start)  return;        console.log("下载实现")        process.exit(1)    })  }  http.get(downloadConfig, request)}process.stdin.on("data", (chunk) => {  if (chunk.toString().includes("p")) {    //键盘p暂停下载    mode = "pause"  } else {    mode = "start"    download()  }})

User-Agent

User-Agent 首部蕴含了一个特色字符串,用来让网络协议的对端来辨认发动申请的用户代理软件的利用类型、操作系统、软件开发商以及版本号。

User-Agent判断是否挪动端,重定向到新地址:

require("http")  .createServer((req, res) => {    const ua = req.headers["user-agent"];    const isMobile = /(iPhone|iPad|iPod|iOS|Android)/i.test(ua);    const redirectUrl = isMobile ? "https://m.58.com/gz" : "https://gz.58.com";        res.statusCode = 302;    res.setHeader("Location", redirectUrl)    res.end()  })  .listen(3000, () => console.log(`Serving on: \r\n  http://localhost:3000`))

Referer

Referer 申请头蕴含了以后申请页面的起源页面的地址,即示意以后页面是通过此起源页面里的链接进入的。服务端个别应用 Referer 申请头辨认拜访起源,可能会以此进行统计分析、日志记录以及缓存优化等。

示例

Referer: https://developer.mozilla.org/en-US/docs/Web/JavaScript

以下两种状况下,Referer 不会被发送:

  • 起源页面采纳的协定为示意本地文件的 "file" 或者 "data" URI
  • 以后申请页面采纳的是非平安协定,而起源页面采纳的是平安协定(HTTPS)

判断盗链示例:

const url = require("url");const http = require("http");http.createServer((req, res) => {    let referer = req.headers["referer"];    if (referer) {        let refererHost = url.parse(referer).host        let host = req.headers["host"];        if(refererHost!==host){            // 被盗链了        }    }}).listen(3000, () => console.log(`Serving on: \r\n  http://localhost:3000`))

Content-Encoding

Content-Encoding 是一个实体音讯首部,用于对特定媒体类型的数据进行压缩。当这个首部呈现的时候,它的值示意音讯主体进行了何种形式的内容编码转换。这个音讯首部用来告知客户端应该怎么解码能力获取在 Content-Type 中标示的媒体类型内容。

个别倡议对数据尽可能地进行压缩,因而才有了这个音讯首部的呈现。不过对于特定类型的文件来说,比方jpeg图片文件,曾经是进行过压缩的了。有时候再次进行额定的压缩无助于负载体积的减小,反而有可能会使其增大。

应用 gzip 形式进行压缩

服务端配置Content-Encoding字段:

Content-Encoding:gzip

客户端应用 Accept-Encoding 字段阐明接管办法:

Accept-Encoding: gzip, deflate

代码实现

const fs = require("fs");const zlib = require("zlib")const http = require("http");http  .createServer((req, res) => {    let encoding = req.headers["accept-encoding"]    if(!encoding) return fs.createWriteStream("./test.html").pipe(res);    if(/\bgzip\b/.test(encoding)){        res.setHeader("Content-Encoding","gzip");        return fs.createWriteStream("./test.html").pipe(zlib.createGzip()).pipe(res)    }    if(/\bdeflate\b/.test(encoding)){        res.setHeader("Content-Encoding", "bdeflate")        return fs.createWriteStream("./test.html").pipe(zlib.createDeflate()).pipe(res)    }  })  .listen(3000, () => console.log(`Serving on: \r\n  http://localhost:3000`))

注意事项

依据HTTP标准,HTTP的音讯头部的字段名,是不辨别大小写的.

3.2. Header Fields
Each header field consists of a case-insensitive field name followed by a colon (”:“), optional leading whitespace, the field value, and optional trailing whitespace.