Accept-Language
Accept-LanguageUsually used to implement Multilingualism:
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)
The order of priority, expressed by relative quality value, is also called weight.
Simple implementation:
const http = require("http")
Const languages = {zh: "hello", 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 protocol scope requests allow the server to send only part of the HTTP message to the client. Range requests are useful when transferring large media files, or when used in conjunction with the breakpoint Resume feature of file downloads.
Response status of the scope request:
206 Partial Content
Service request successful416 Requested Range Not Satisfiable
Request range out of range (range value exceeds the size of the resource)200 OK
The scope request is not supported to return the entire resource. When downloading in sections, you should judge first
Range
Request header:
Range: bytes=start-end
Range: bytes=10-
: data of the 10th and last byteRange: bytes=40-100
: data between the 40th and 100th bytes
Note that this indicates [start, end], which contains the start and end bytes of the request header. Therefore, the next request should be the [end + 1, nexend] of the previous request
Content-Range
Response head
//The server responded to the first (0-10) bytes of data. The resource has a total size of (3103) bytes.
Content-Range: bytes 0-10/3103;
//The server responded to 11 bytes of data (0-10)
Content-Length: 11;
code implementation
Server side pressrange
Scope Download
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"]
//No range directly returns the file
if (!range) return fs.createReadStream(DOWNLOAD_FILE).pipe(res)
//There are other uses for intercepting range values. The case of separation is not considered here
let [, start, end] = range.match(/(\d*)-(\d*)/)
start = start ? start * 1 : 0
end = end ? end * 1 : TOTAL
//Range request success status code 206 Partial Content
res.statusCode = 206
//Set response header
res.setHeader("Content-Range", `bytes ${start}-${end}/${TOTAL}`)
//Return range data
fs.createReadStream(DOWNLOAD_FILE, { start, end }).pipe(res)
}).listen(3000, () => console.log(`Serving on 3000`))
Client download
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 = 0
Let mode = "start" // download mode "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
//Print download progress
console.clear();
console.log (` download progress:${ Math.min (parseInt ((start / total) * 100), 100)}% \ \ press P and enter to pause ')
setTimeout(()=>{
//If mode is start mode, continue downloading
mode === "start" ? download() : console.log ("pause download, press any key to enter to download)"
},1000)
} else {ws.end()}
})
res.on("end", () => {
if (total > start) return;
console.log (download complete)
process.exit(1)
})
}
http.get(downloadConfig, request)
}
process.stdin.on("data", (chunk) => {
if (chunk.toString().includes("p")) {
//Keyboard P pause Download
mode = "pause"
} else {
mode = "start"
download()
}
})
User-Agent
User-AgentThe first part contains a character string, which enables the peer of the network protocol to identify the application type, operating system, software developer and version number of the user agent software that initiates the request.
User-Agent
Determine whether the mobile terminal is mobile and redirect to the new address:
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
RefererThe request header contains the address of the source page of the current request page, which means that the current page is entered through the link in the source page. The server generally uses the referer request header to identify the access source, which may be used for statistical analysis, logging and cache optimization.
Examples
Referer: https://developer.mozilla.org/en-US/docs/Web/JavaScript
Referers are not sent in the following two cases:
- The protocol adopted by the source page is the “file” or “data” URI representing the local file
- The current request page adopts the non security protocol, while the source page uses the secure protocol (HTTPS)
Example of judging chain theft:
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){
//Stolen chain
}
}
}).listen(3000, () => console.log(`Serving on: \r\n http://localhost:3000`))
Content-Encoding
Content-EncodingIs an entity message header used to compress data of a specific media type. When the header appears, its value indicates how the message body performs content encoding transformation. The header of this message is used to tell the client how to decode the media type content marked in the content type.
It is generally recommended that the data be compressed as much as possible, so that the header of this message appears.However, for certain types of files, such as JPEG image files, are already compressed. Sometimes additional compression does not help to reduce the load volume, but may increase it.
usegzip
Mode
Server configurationContent-Encoding
Field:
Content-Encoding:gzip
Client useAccept-Encoding
Field description receiving method:
Accept-Encoding: gzip, deflate
code implementation
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`))
matters needing attention
According to the HTTP specification, the field name of the HTTP message header is case insensitive
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.