node http模块

http的那些事儿

请问你对http了解吗?javascript

  • 还比较了解。HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议, 同一个客户端的此次请求和上次请求是没有对应关系。HTTP协议永远都是客户端发起请求,服务器回送响应。见下图:
    pkg

一个网页的加载过程是什么样的?php

  • 浏览器会因页面上的css/js/image等静态资源会屡次发起链接请求,能够把这个过程分红两部分css

    • html(jsp/php/aspx) 页面加载(假设存在简单的Nginx负载均衡)
    • css/js/image等 网页静态资源加载(假设使用CDN)
  • 整个过程大体通过了 DNS解析 --> 负载均衡 --> web服务器 --> 浏览器渲染html

    • DNS解析: 将域名地址解析为对应的ip地址的过程。
    • 创建TCP链接
    • 发起Http请求,请求网页, 其中, 请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。
    • 服务器返回请求页面:其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。
    • 浏览器渲染: 根据页面内容,生成DOM Tree;根据CSS内容,生成CSS Rule Tree; 调用JS执行引擎执行js代码。根据DOM Tree和CSS Rule Tree生成Render Tree(呈现树)。根据Render Tree渲染网页.
  • 可是在浏览器解析页面内容的时候,会发现页面引用了其余未加载的image、css文件、js文件等静态内容,所以开始了第二部分的静态资源请求。java

经常使用的请求方法有哪些web

  • GET/POST/PUT/DELETE/TRACE/OPTION/HEAD/CONNECT/PATCH

经常使用的Http 请求头字段有哪些?算法

  • Accept:浏览器端能够接受的MIME类型vim

    • MIME类型:
      • application: 某种二进制附件,对于没有subtype的状况,默认是application/octet-stream
      • text: 文本,理论上可读,对于没有subtype的状况,默认是text/plain
      • image: 图像
      • audio: 音频
      • video: 视频
      • multipart: 多部分文档文件(复合文档文件)
  • Accept-Charset 设置接受的字符编码跨域

  • Accept-Encoding 设置接受的编码格式浏览器

  • Accept-Language 设置接受的语言

  • Authorization 设置HTTP身份验证的凭证

  • Cache-Control 设置请求响应链上全部的缓存机制必须遵照的指令

  • Content-Length 设置请求体的字节长度

  • Content-MD5 设置基于MD5算法对请求体内容进行Base64二进制编码

  • Content-Type 设置请求体的MIME类型(适用POST和PUT请求)

  • Cookie 设置服务器使用Set-Cookie发送的http cookie

  • Date 设置消息发送的日期和时间

  • Expect 标识客户端须要的特殊浏览器行为

  • Host 设置服务器域名和TCP端口号,若是使用的是服务请求标准端口号,端口号能够省略

  • If-Match 设置客户端的ETag,当时客户端ETag和服务器生成的ETag一致才执行,适用于更新自从上次更新以后没有改变的资源

  • If-Modified-Since 设置更新时间,从更新时间到服务端接受请求这段时间内若是资源没有改变,容许服务端返回304 Not Modified

  • If-None-Match 设置客户端ETag,若是和服务端接受请求生成的ETage相同,容许服务端返回304 Not Modified

  • If-Range 设置客户端ETag,若是和服务端接受请求生成的ETage相同,返回缺失的实体部分;不然返回整个新的实体

  • Forwarded 披露客户端经过http代理链接web服务的源信息

    • Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43
    • Forwarded: for=192.0.2.43, for=198.51.100.17
  • If-Unmodified-Since 设置更新时间,只有从更新时间到服务端接受请求这段时间内实体没有改变,服务端才会发送响

  • Max-Forwards 限制代理或网关转发消息的次数

  • Origin 标识跨域资源请求(请求服务端设置Access-Control-Allow-Origin响应字段)

  • Pragma 设置特殊实现字段,可能会对请求响应链有多种影响

  • Proxy-Authorization 为链接代理受权认证信息

  • Range 请求部分实体,设置请求实体的字节数范围,具体能够参见HTTP/1.1中的Byte serving

    • Range: bytes=500-999
  • Referer 设置前一个页面的地址,而且前一个页面中的链接指向当前请求,意思就是若是当前请求是在A页面中发送的,那么referer就是A页面的url地址

  • Upgrade 请求服务端升级协议

  • User-Agent 用户代理的字符串值

  • Via 通知服务器代理请求

  • Warning 实体可能会发生的问题的通用警告

经常使用的Http 响应头字段有哪些?

  • Access-Control-Allow-Origin 指定哪些站点能够参与跨站资源共享
  • Accept-Patch 指定服务器支持的补丁文档格式,适用于http的patch方法
    • Accept-Patch: text/example;charset=utf-8
  • Accept-Ranges 服务器经过byte serving支持的部份内容范围类型
  • Age 对象在代理缓存中暂存的秒数
  • Allow 设置特定资源的有效行为,适用方法不被容许的http 405错误
  • Content-Encoding 设置数据使用的编码类型
  • Content-Language 为封闭内容设置天然语言或者目标用户语言
  • Content-Length 响应体的字节长度
  • Content-Location 设置返回数据的另外一个位置
  • Content-MD5 设置基于MD5算法对响应体内容进行Base64二进制编码
  • Content-Range 标识响应体内容属于完整消息体中的那一部分
  • Content-Type 设置响应体的MIME类型
  • ETag 特定版本资源的标识符,一般是消息摘要
  • Expires 设置响应体的过时时间
  • Last-Modified 设置请求对象最后一次的修改日期
  • Set-Cookie 设置HTTP Cookie
  • Server 服务器名称
  • Status 设置HTTP响应状态
  • Transfer-Encoding 设置传输实体的编码格式,目前支持的格式: chunked, compress, deflate, gzip, identity
  • Upgrade 请求客户端升级协议

http的响应状态码

  • 1xx Informational(信息性状态码)

  • 2XX Success(成功状态码)

    1. 200(OK 客户端发过来的数据被正常处理
    2. 204(Not Content 正常响应,没有实体
    3. 206(Partial Content 范围请求,返回部分数据,响应报文中由Content-Range指定实体内容
  • 3xx Redirection(重定向)

    1. 301(Moved Permanently) 永久重定向
    2. 302(Found) 临时重定向,规范要求方法名不变,可是都会改变
    3. 303(See Other) 和302相似,但必须用GET方法
    4. 304(Not Modified) 状态未改变 配合(If-Match、If-Modified-Since、If-None_Match、If-Range、If-Unmodified-Since)
    5. 307(Temporary Redirect) 临时重定向,不应改变请求方法
  • 4XX Client Error(客户端错误状态码)

    1. 400(Bad Request) 请求报文语法错误
    2. 401 (unauthorized) 须要认证
    3. 403(Forbidden) 服务器拒绝访问对应的资源
    4. 404(Not Found) 服务器上没法找到资源
  • 5xx Server Error(服务器错误状态码)

    1. 500(Internal Server Error)服务器故障
    2. 503(Service Unavailable) 服务器处于超负载或正在停机维护

url模块

url.parse(urlStr,[parseQueryString]);
复制代码
  • href 被转换的原URL字符串
  • protocal 客户端发出请求时使用的协议
  • slashes 在协议与路径之间是否使用了//分隔符
  • host URL字符串中的完整地址和端口号
  • auth URL字符串中的认证部分
  • hostname URL字符串中的完整地址
  • port URL字符串中的端口号
  • pathname URL字符串的路径,不包含查询字符串
  • search 查询字符串,包含?
  • path 路径,包含查询字符串
  • query 查询字符串,不包含起始字符串?
  • hash 散列字符串,包含#

http的应用

1. 范围请求 206

客户端须要发送一个Range:bytes=0-5 服务器 Sccept-Range:bytes Content-Range: bytes 0-5/705

// 在命令行模式范围请求
    curl -v --header "Range: bytes=0-5" http://www.baidu.com/img/baidu_jgylogo3.gif 
复制代码

server.js

let http = require('http')
    let path = require('path')
    let p = path.resolve(__dirname, '1.txt');
    let fs = require('mz/fs')
    const port = 3000;
    
    async function listener(req, res) {
        let range = req.headers['range'];
        if (range) {
            let [, start, end] = range.match(/(\d*)-(\d*)/);
            let statObj = await fs.stat(p);
            let total = statObj.size;
            start = start ? Number(start) : 0;
            end = end ? Number(end) : total - 1;
            res.statusCode = 206;
            res.setHeader('Accept-Ranges', 'bytes');
            res.setHeader('Content-Range', `bytes ${start}-${end}/${total}`);
            fs.createReadStream(p, {start, end, encoding: 'utf8'}).pipe(res);
        } else {
            // 读取文件 并响应给客户端
            fs.createReadStream(p).pipe(res)
        }
    }
    
    let server = http.createServer(listener);
    server.listen(port, () => {
        console.log(`server start at ${port}`)
    })
复制代码

client.js

// 定时发起请求,并把请求到的结果写入download.txt,实现断点续传的功能
    
    let http = require('http');
    let fs = require('fs');
    let ws = fs.createWriteStream(__dirname + '/download.txt')
    let start = 0;
    const unit = 4;
    let config = {
        host: 'localhost',
        port: 3000
    }
    
    function download() {
        config.headers = {
            'Range': `bytes=${start}-${start + unit}`
        }
        start += 5;
        let client = http.request(config, res => {
            let total = res.headers['content-range'].split('/')[1];
            let buffers = [];
            res.on('data', data => {
                buffers.push(data);
            });
            res.on('end', () => {
                let result = Buffer.concat(buffers);
                ws.write(result)
                setTimeout(() => {
                    console.log('start <= total', start, total)
                    if (start <= total) {
                        download();
                    }
                }, 1000);
            })
        })
        client.end(); // 必须调用end 不然不会发送内容
    }
    download();
复制代码

2. 防盗链

server.js

/** * 实现原理 * host: 表示资源的地址,通常是服务器地址,默认端口号80 * refer/referered: 使用资源的端地址 * * 在服务器端配置资源可访问的白名单 WHITELIST, * 当host与refer/referered的域名不相同,而且refer/referered的地址在WHITELIST中时, * 表示能够该端能够访问服务器中的资源,不然不可访问. * */ 
    
    let http = require('http');
    let fs = require('fs');
    let url = require('url');
    let path = require('path');
    let static = path.resolve(__dirname);
    const WHITELIST = ['linda_1.cn'];
    let server = http.createServer(async (req, res) => {
        let { pathname } = url.parse(req.url);
        let p = path.join(static, pathname);
        let flag = true;
        try{
            fs.accessSync(p)
        } catch(e) {
            flag = false;
        }
        if (flag) {
            let refer = req.headers['referer'] || req.headers['referered'];
            if (refer) {
                let hostname = req.headers['host'].split(':')[0];
                let refername = url.parse(refer).hostname;
                if (refername != hostname && !WHITELIST.includes(refername)) {
                    fs.createReadStream(path.join(static, '/images/girl.png')).pipe(res);
                } else {
                    fs.createReadStream(p).pipe(res);
                }
            } else {
                fs.createReadStream(p).pipe(res);
            }
        } else{
            res.statusCode = 404;
            res.end();
        }
    })
    
    server.listen(3000, () => {
        console.log('server is starting on 3000...')
    })
复制代码

index.html

<!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Page Title</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
        <img src="http://localhost:3000/images/boy.png"/>
    </body>
    </html>
复制代码

mac下配置域名与主机名映射

vim /etc/hosts

127.0.0.1 linda_1.cn
    127.0.0.1 linda_2.cn
复制代码

配置好后,可在浏览器中输入不一样的域名,来测试图片的显示状况。

相关文章
相关标签/搜索