zoukankan      html  css  js  c++  java
  • 基于NodeJS的网络响应原理与HTTP协议

    服务器端基础概念

    • 网站的组成

      • 网站应用程序主要分为两大部分:客户端和服务器端。
      • 客户端:在浏览器中运行的部分,就是用户看到并与之交互的界面程序。使用HTML、CSS、JavaScript构建。
      • 服务器端:在服务器中运行的部分,负责存储数据和处理应用逻辑。
    • Node网站服务器

      • 能够提供网站访问服务的机器就是网站服务器,它能够接收客户端的请求,能够对请求做出响应。
    • IP地址

      • 互联网中设备的唯一标识。
      • IP是Internet Protocol Address的简写,代表互联网协议地址.
    • 域名

      • 由于IP地址难于记忆,所以产生了域名的概念,所谓域名就是平时上网所使用的网址。
      • 域名解析:http://www.itheima.com => http://124.165.219.100/
      • 虽然在地址栏中输入的是网址, 但是最终还是会将域名转换为ip才能访问到指定的网站服务器。
    • 端口

      • 端口是计算机与外界通讯交流的出口,用来区分服务器电脑中提供的不同的服务。
    • URL

      • 统一资源定位符,又叫URL(Uniform Resource Locator),是专为标识Internet网上资源位置而设的一种编址方式,我们平时所说的网页地址指的即是URL。
      • URL的组成
    • 开发过程中客户端和服务器端说明

      • 在开发阶段,客户端和服务器端使用同一台电脑,即开发人员电脑
      • 本机域名:localhost
      • 本地IP:127.0.0.1

    创建Web服务器

    • 创建Web服务器
      // 引用系统模块,用于创建网站服务器模块
     const http = require('http');
      // 创建web服务器,app对象就是网站服务器对象
     const app = http.createServer();
      // 当客户端发送请求的时候
     app.on('request', (req, res) => {
            //  响应
           res.end('<h1>hi, user</h1>');
     });
      // 监听3000端口
     app.listen(3000);
     console.log('服务器已启动,监听3000端口,请访问 localhost:3000');
    

    HTTP协议

    • HTTP协议的概念

      • 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)规定了如何从网站服务器传输超文本到本地浏览器
      • 它基于客户端服务器架构工作,是客户端(用户)和服务器端(网站)请求和应答的标准。
    • 报文

      • 在HTTP请求和响应的过程中传递的数据块就叫报文,
      • 包括要传送的数据和一些附加信息,并且要遵守规定好的格式。
      • 请求报文
      • 响应报文
    • 请求报文

      • Request Headers 客户端给服务器的请求内容
        • req.headers
      • Accept 请求文件的格式
        • req.headers.accept
      • 请求方式 (Request Method)
        • req.method
        • GET 请求数据
        • POST 发送数据
      • 请求地址 (Request URL)
        • req.url
     app.on('request', (req, res) => {
         req.headers  // 获取请求报文
         req.url      // 获取请求地址
         req.method   // 获取请求方法
     });
    
    // 用于创建网站服务器模块
    const http = require('http');
    // app对象就是网站服务器对象
    const app = http.createServer();
    // 当客户端有请求来的时候
    // req请求对象,res响应数据
    app.on('request', (req, res)=> {
        // 设置响应报文
        res.writeHead(200, {       
            'Content-Type': 'text/html;charset=utf8'
        });
        // 获取请求方式
        console.log(req.method);
        // 获取请求报文信息
        console.log(req.headers);
        // 获取请求地址
        console.log(req.url);
        if(req.url == '/index' || '/'){
            res.end('欢迎来到首页!');
        }else if(req.url == '/list'){
            res.end('欢迎来到列表页!');
        }else{
            res.end('找不到了哦!');
        }
    
        if(req.method == 'POST'){
            res.end('输出 POST');
        }else if(req.method == 'GET'){
            res.end('输出 GET');
        }
        // res.end('<h2>hello user</h2>');
    })
    // 监听3000端口
    app.listen(3000);
    console.log('网站服务器启动成功!');
    
    • 响应报文
      • Response Headers 服务器响应给客户端的内容
      • HTTP状态码
        • 200 请求成功
        • 404 请求的资源没有被找到
        • 500 服务器端错误
        • 400 客户端请求有语法错误
      • 内容类型
        • text/html
        • text/css
        • text/plain 纯文本,默认值
        • application/javascript
        • image/jpeg
        • application/json
     app.on('request', (req, res) => {
         // 设置响应报文
         res.writeHead(200, {       
           'Content-Type': 'text/html;charset=utf8';
         });
     });
    

    HTTP请求与响应处理

    • 请求与响应
      • POST 客户端发出请求
      • GET 服务器得到响应
      // 表单请求
      <form method="post" action='http://localhost:3000'>
        <input type="submit" name="" value="请求提交">
      </form>
    
    // 用于创建网站服务器模块
    const http = require('http');
    // app对象就是网站服务器对象
    const app = http.createServer();
    // 当客户端有请求来的时候
    // req请求对象,res响应数据
    app.on('request', (req, res)=> {
        // 设置响应报文
        res.writeHead(200, {       
            'Content-Type': 'text/html;charset=utf8'
        });
        // 响应状态码
        console.log(res.statusCode);
        if(req.method == 'POST'){
            res.end('输出 POST');
        }else if(req.method == 'GET'){
            res.end('输出 GET');
        }
        res.end('<h2>hello user</h2>');
    })
    // 监听3000端口
    app.listen(3000);
    console.log('网站服务器启动成功!');
    
    • 请求参数

      • 客户端向服务器端发送请求时,有时需要携带一些客户信息,客户信息需要通过请求参数的形式传递到服务器端,比如登录操作。
    • GET请求参数

      • 参数被放置在浏览器地址栏中,例如:http://localhost:3000/?name=zhangsan&age=20
      • 参数获取需要借助系统模块url,url模块用来处理url地址
        • const url = require('url');
     const http = require('http');
     // 导入url系统模块 用于处理url地址
     const url = require('url');
     const app = http.createServer();
     app.on('request', (req, res) => {
         // 将url路径的各个部分解析出来并返回对象
             // true 代表将参数解析为对象格式
         let {query} = url.parse(req.url, true);
         console.log(query);
     });
     app.listen(3000);
    
     const http = require('http');
     // 导入url系统模块 用于处理url地址
     const url = require('url');
     const app = http.createServer();
     app.on('request', (req, res) => {
        // 返回查询参数的另一种写法
        console.log(url.parse(req.url));
        let params = url.parse(req.url, true).query;
        console.log(params.name);
        console.log(params.age);
    
        // 将url路径的各个部分解析出来并返回对象
        // true 代表将参数解析为对象格式
        let {query, pathname} = url.parse(req.url, true);
        console.log(query.name);
        console.log(query.age);
        console.log(pathname);
    
        if(pathname == '/index' || pathname == '/'){
            res.end('<h2>欢迎来到首页!</h2>');
        }else if(pathname == '/list'){
            res.end('欢迎来到列表页!');
        }else{
            res.end('404,找不到了哦!');
        }
     });
     app.listen(3000);
    
    • POST请求参数
      • 参数被放置在请求体中进行传输(报文)
      • 获取POST参数需要使用data事件和end事件
      • 使用querystring系统模块将参数转换为对象格式
     // 导入系统模块querystring 用于将HTTP参数转换为对象格式
     const querystring = require('querystring');
     app.on('request', (req, res) => {
         let postData = '';
         // 监听参数传输事件
         req.on('data', (chunk) => postData += chunk;);
         // 监听参数传输完毕事件
         req.on('end', () => { 
             console.log(querystring.parse(postData)); 
         }); 
     });
    
    • 路由
      • http://localhost:3000/index
      • http://localhost:3000/login
      • 路由是指客户端请求地址与服务器端程序代码的对应关系。简单的说,就是请求什么响应什么。
     // 当客户端发来请求的时候
     app.on('request', (req, res) => {
         // 获取客户端的请求路径
         let { pathname } = url.parse(req.url);
         if (pathname == '/' || pathname == '/index') {
             res.end('欢迎来到首页');
         } else if (pathname == '/list') {
             res.end('欢迎来到列表页页');
         } else {
            res.end('抱歉, 您访问的页面出游了');
         }
     });
    
    • 静态资源
      • 服务器端不需要处理,可以直接响应给客户端的资源就是静态资源
      • 例如CSS、JavaScript、image文件。
      • http://www.itcast.cn/images/logo.png
    const http = require('http');
    const url = require('url');
    const path = require('path');
    const fs = require('fs');
    // 文件类型模块
    const mime = require('mime');
    const app = http.createServer();
    app.on('request', (req, res) => {
        // 获取请求路径
        let pathname = url.parse(req.url).pathname;
        pathname = pathname == '/' || pathname == '/index.html' ? '/default.html' : pathname;
        // 将用户的请求路径转换为实际的服务器硬盘路径
        // console.log(path.join(__dirname));
        let realPath = path.join(__dirname, 'public' + pathname);
        // 根据路径 返回文件类型
        let type = mime.getType(realPath);
        console.log(type);
        // 读取文件
        fs.readFile(realPath, (error, result) => {
            if(error != null){
                res.writeHead(404, {       
                    'Content-Type': 'text/html;charset=utf8'
                });
                res.end('文件读取失败!');
                return;
            }
            res.writeHead(200, {       
                'Content-Type': type
            });
            res.end(result);
        });
    });
    app.listen(3000);
    console.log('网络服务器启动成功!');
    
    • 动态资源
      • 相同的请求地址不同的响应资源,这种资源就是动态资源。
      • http://www.itcast.cn/article?id=1
      • http://www.itcast.cn/article?id=2

    Node.js异步编程

    • 同步API与异步API

      • 同步API:只有当前API执行完成后,才能继续执行下一个API
      • 异步API:当前API的执行不会阻塞后续代码的执行
      • 同步API可以从返回值中拿到API执行的结果, 但是异步API是不可以的
      • 同步API从上到下依次执行,前面代码会阻塞后面代码的执行
      • 异步API不会等待API执行完成后再向下执行代码
    • 使用回调函数获取异步API执行结果

      • 回调函数:自己定义函数让别人去调用。
      • 异步处理函数是通过回调函数进行数据传递的
    function getMsg (callback) {
        setTimeout(function () {
            callback ({ msg: 'Hello Node.js' })
        }, 2000);
    }
    getMsg (function (msg) { 
        console.log(msg);
    });
    
    • 回调地狱
    fs.readFile('./1.txt', 'utf8', (err, result1) => {
    	console.log(result1)
    	fs.readFile('./2.txt', 'utf8', (err, result2) => {
    		console.log(result2)
    		fs.readFile('./3.txt', 'utf8', (err, result3) => {
    			console.log(result3)
    		})
    	})
    });
    

    Node.js中的异步API

    • Promise
      • Promise出现的目的是解决Node.js异步编程中回调地狱的问题。
      • 回调函数中的结果与错误分离,并将数据外调使用
      • promise返回值为promise对象
      • then接受promise对象中的数据
      • catch接受promise对象错误
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            if (true) {
                resolve({name: '张三'})
            }else {
                reject('失败了') 
            } 
        }, 2000);
    });
    promise.then(result => console.log(result); )// {name: '张三'}
           .catch(error => console.log(error); )// 失败了
    
    const fs = require('fs');
    let promise = new Promise((resolve, reject) => {
    	fs.readFile('./300.txt', 'utf8', (err, result) => {
    		if (err != null) {
    			reject(err);
    		}else {
    			resolve(result);
    		}
    	});
    });
    promise.then((result) => {
    	 console.log(result);
    })
    .catch((err)=> {
    	console.log(err);
    })
    
    const fs = require('fs');
    function p1 () {
    	return new Promise ((resolve, reject) => {
    		fs.readFile('./1.txt', 'utf8', (err, result) => {
    			resolve(result)
    		})
    	});
    }
    function p2 () {
    	return new Promise ((resolve, reject) => {
    		fs.readFile('./2.txt', 'utf8', (err, result) => {
    			resolve(result)
    		})
    	});
    }
    function p3 () {
    	return new Promise ((resolve, reject) => {
    		fs.readFile('./3.txt', 'utf8', (err, result) => {
    			resolve(result)
    		})
    	});
    }
    p1().then((r1)=> {
    	console.log(r1);
    	return p2();
    })
    .then((r2)=> {
    	console.log(r2);
    	return p3();
    })
    .then((r3) => {
    	console.log(r3)
    })
    
    • 异步函数

      • 异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了。
    • async 关键字

      • 普通函数定义前加async关键字 普通函数变成异步函数
      • 异步函数默认的返回值是promise对象
      • 在异步函数内部使用return关键字进行结果返回 结果会被包裹的promise对象中
      • return关键字代替了resolve方法
      • 在异步函数内部使用throw关键字抛出程序异常
      • 调用异步函数再链式调用then方法获取异步函数执行结果
      • 调用异步函数再链式调用catch方法获取异步函数执行的错误信息
    async function fn(){
        throw '发生了一些错误';
        return '异步函数返回值';
    }
    // console.log(fn());
    fn().then(function(data){
        console.log(data);
    }).catch(function(error){
        console.log(error);
    })
    
    • await关键字
      • 它只能出现在异步函数中
      • await promise 它可以暂停异步函数的执行 等待promise对象返回结果后再向下执行函数
      • await关键字可是暂停异步函数向下执行 直到promise返回结果
      • await后面只能写promise对象 写其他类型的API是不可以的
      • 等待promise对象返回结果后再向下执行函数
      • 在异步函数内部使用throw关键字进行错误的抛出
    async function p1 () {
      return 'p1';
    }
    async function p2 () {
      return 'p2';
    }
    async function p3 () {
      return 'p3';
    }
    (async function run () {
      let r1 = await p1();
      let r2 = await p2();
      let r3 = await p3();
      console.log(r1);
      console.log(r2);
      console.log(r3);
    })()
    
    const fs = require('fs');
    // 改造现有异步函数api 让其返回promise对象 从而支持异步函数语法
    const promisify = require('util').promisify;
    // 调用promisify方法改造现有异步API 让其返回promise对象
    const readFile = promisify(fs.readFile);
    (async function run () {
    	let r1 = await readFile('./1.txt', 'utf8');
    	let r2 = await readFile('./2.txt', 'utf8');
    	let r3 = await readFile('./3.txt', 'utf8');
    	console.log(r1);
    	console.log(r2);
    	console.log(r3);
    })();
    
  • 相关阅读:
    YouTube视频搬运核心技术公布,月赚3万美金
    如何发掘各种暴利的赚钱项目,如何知道别人在干什么赚钱
    新手操作孕妇防辐射服暴利项目,也能日入500+
    最有效的赚钱方法,只有100元如何赚到10万?
    利用音频平台日引1000宝妈粉,轻松日赚500+
    微信小程序的另类玩法,新手也能日赚一千
    手把手教你如何复制暴利项目
    通过小红书精准引流女性粉丝,日赚1000+的网赚项目
    Android客户端与服务器的交互(增删改查)之干货篇(内含代码)
    linux下安装redis
  • 原文地址:https://www.cnblogs.com/SharkJiao/p/13660330.html
Copyright © 2011-2022 走看看