zoukankan      html  css  js  c++  java
  • 如何创建一个网站服务器

    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); // 这里的端口号可以随便写,不一定是3000
    console.log('服务器已启动,监听3000端口,请访问localhost:3000');
    // 在powerShall中输入 nodemon app.js启动服务器,再在浏览器中输入localhost:3000
    

    2. HTTP协议

    2.1 http协议的概念

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

    2.2 报文

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

    2.3 请求报文

    获取请求方式:req.method

    1. 请求方式(Request Method)
    • GET 请求数据
      在浏览器中输入网址使用的是get请求

    • POST 发送数据
      如何发送post请求:使用表单方式

    <body>
        <!-- 
            method: 指定当前表单提交的方式
            action:指定当前表单提交的地址
         -->
        <form method="post" action="http://localhost:3000">
            <input type="submit">
        </form>
    </body>
    

    1. 请求地址(Request URL)
        // 获取请求地址
        // req.url
    

    2.4 响应报文

    1. HTTP状态
    • 200 请求成功
    • 404 请求的资源没有被找到
    • 500 服务器端错误
    • 400 客户端请求有语法错误

    3. HTTP请求与响应处理

    3.1 请求参数

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

    3.2 GET请求参数

    // 用于创建网站服务器的模块
    // 引用系统模块
    const http = require('http');
    // 用于处理url地址
    const url = require('url');
    
    // 创建web服务器
    // app对象就是网站服务器对象
    const app = http.createServer();
    
    // 当客户端发送请求的时候
    app.on('request', (req, res) => {
        console.log(req.url);
        // url.parse的参数:1)要解析的url地址 2)将查询参数解析成对象形式
        let { query, pathname } = url.parse(req.url, true);
        console.log(query.name);
        console.log(query.age);
    
        if (pathname == '/index' || pathname == '/') {
            return res.end('<h2>欢迎来到首页</h2>');
        } else if (pathname == '/list') {
            return res.end('welcome to listpage');
        } else {
            return res.end('no find');
        }
    });
    // 监听3000端口
    app.listen(3000);
    console.log('服务器已启动,监听3000端口,请访问localhost:3000');
    // 在powerShall中输入 nodemon app.js启动服务器,再在浏览器中输入localhost:3000
    

    3.3 POST请求参数

    • 参数被放置在请求体中进行传输
    • 获取POST参数需要使用data事件和end事件
    • 使用querystring系统模块将参数转换为对象格式
    // 导入系统模块querystring 用于将HTTP参数转换为对象格式
    const querystring = require('querystring');
    app.on('request', (req, res) => {
        let postData = '';
        // 监听参数传输事件
        // post参数是通过事件的方式接受的
        // data: 但请求参数传递的时候触发data事件
        // end:当参数传递完成的时候触发end事件
    
        req.on('data', (chunk) => postData += chunk;);
        // 监听参数传输完毕事件
        req.on('end', () => { 
            console.log(querystring.parse(postData)); 
        }); 
    });
    

    3.4 路由

    http://localhost:3000/index 首页
    http://localhost:3000/login 登录页面
    路由是指客户端请求地址与服务器端程序代码的对应关系。简单来说,就是请求什么响应什么

     // 1. 引入系统模块http
    // 2. 创建网站服务器
    // 3. 为网站服务器对象添加请求事件
    // 4. 实现路由功能
    // 1) 获取客户端的请求方式
    // 2) 获取客户端的请求地址
    const http = require('http');
    const url = require('url')
    const app = http.createServer();
    
    app.on('request', (req, res) => {
    
        // 获取请求方式
        const method = req.method.toLowerCase();
    
        // 获取请求地址
        const pathname = url.parse(req.url).pathname;
    
        res.writeHead(200, {
            'content-type': 'text/html;charset=utf8'
        })
    
        if (method == 'get') {
            if (pathname == '/' || pathname == '/index') {
                return res.end('欢迎来到首页')
            } else if (pathname == '/list') {
                return res.end('欢迎来到列表页');
            } else {
                return res.end('您访问的页面不存在');
            }
        } else if (method == 'post') {
            if (pathname == '/' || pathname == '/index') {
                return res.end('欢迎来到首页')
            } else if (pathname == '/list') {
                return res.end('欢迎来到列表页');
            } else {
                return res.end('您访问的页面不存在');
            }
        }
    });
    
    app.listen(3000);
    console.log('服务器启动成功');
    

    3.5 静态资源

    服务器端不需要处理,可以直接响应客户端的资源就是静太资源,例如CSS、JavaScript、image文件。

    3.6 动态资源

    相同的请求地址不同的响应资源,这种资源就是动态资源。
    例如:
    http:www.itcast.cn/article?id=1
    http:www.itcast.cn/article?id=2

    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 == '/' ? 'default.html' : pathname;
    
        // res.writeHead(200, {
        //     'content-type': 'text/html;charset=utf8'
        // })
    
        // 将用户的请求路劲转换为实际的服务器硬盘路劲
        let realPath = path.join(__dirname, 'public' + pathname);
    
        let type = mime.getType(realPath);
    
        // 读取文件
        // 如果文件读取成功 error为空,result 就是文件的内容
        // 如果文件读取失败 error里面存储的是失败信息, result为空
        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('服务器启动成功');
    

    4. Node.js异步编程

    4.1 同步API,异步API

    同步API:只有当前API执行完成后,才能继续执行下一个API

    异步API:当前API的执行不会阻塞后续代码的执行

    console.log('before');
    
    setTimeout(function() {
        console.log('last');
    }, 2000);
    
    console.log('after');
    
    // 输出结果为:before after last
    

    4.2 同步API,异步API的区别(获取返回值)

    同步API可以返回值中拿到API执行的结果,但是异步API是不可以的

    // 同步
    function sum(n1, n2) {
        return n1 + n2;
    };
    console.log(sum(2, 3));
    
    // 返回值为:5
    
    // 异步
    function getMsg() {
        setTimeout(function() {
            return {
                msg: 'hello node.js'
            }
        }, 2000);
        // 由于在执行getMsg时,遇到定时器所以直接跳到定时器的后面,添加return undefined执行,将其值返回给msg
        // return undefined
    }
    const msg = getMsg();
    
    console.log(msg);
    
    // 返回值为undefined
    

    4.3 回调函数

    自己定义函数让别人去调用

    // 异步
    function getMsg(callback) {
        setTimeout(function() {
            callback({
                msg: 'hello node.js'
            });
        }, 2000);
    
    }
    getMsg(function(date) {
        console.log(date);
    });
    
    

    4.4 同步API,异步API的区别(代码执行顺序)

    同步API从上到下依次执行,前面代码会阻塞后面代码的执行

    for (var i = 0; i < 10000; i++) {
        console.log(i);
    }
    console.log('执行后面的代码');
    

    异步API不会等待API执行完成后再向下执行代码

    console.log('代码开始执行');
    setTimeout(() => {
        console.log('2秒后执行的代码');
    }, 2000);
    setTimeout(() => {
        console.log('0秒后执行的代码');
    }, 0);
    console.log('代码结束执行');
    // 代码的执行结果
    // 代码开始执行
    // 代码结束执行
    // 0秒后执行的代码
    // 2秒后执行的代码
    

    4.5 代码执行顺序分析

    console.log('代码开始执行');
    setTimeout(() => {
        console.log('2秒后执行的代码');
    }, 2000); 
    setTimeout(() => {
        console.log('"0秒"后执行的代码');
    }, 0);
    console.log('代码结束执行');
    

    4.6 Node.js中的异步API

    const fs = require('fs');
    fs.readFile('1.txt', 'utf-8', (err, result1) => {
        console.log(result1);
        fs.readFile('2.txt', 'utf-8', (err, result2) => {
            console.log(result2);
            fs.readFile('3.txt', 'utf-8', (err, result3) => {
                console.log(result3);
            })
        })
    })
    

    如果异步API后面代码的执行依赖当前异步API的执行结果,但实际上后续代码在执行的时候异步API还没有返回结果,这个问题怎么解决呢?

    const fs = require('fs');
    
    let promise = new Promise((resolve, reject) => {
        fs.readFile('100.txt', 'utf8', (err, result) => {
            if (err != null) {
                return reject(err);
            } else {
                return resolve(result);
            }
        });
    });
    
    promise.then((result) => {
            console.log(result);
        })
        .catch((err) => {
            console.log(err);
        })
    

    4.7 Promise

    Promise出现的目的是解决Node.js异步编程中回调地狱的问题。

    4.8 异步函数

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

    const fn = async () => {}
    
    async function fn() {}
    

    async关键字

    1. 普通函数定义前家async关键字 普通函数变成异步函数
    2. 异步函数默认返回promise对象
    3. 在一部函数内部使用return关键字进行结果返回,结果会包裹的promise对象中return关键字代替了resolve方法
    4. 在一部函数内部使用throw关键字抛出程序异常
    5. 调用异步函数再链式调用then方法获取函数执行结果
    6. 调用异步函数再链式调用catch方法获取异步函数执行的错误信息

    await

    1. await关键字只能出现在异步函数中
    2. await promise await后面只能写promise对象 写其他类型的API是不不可以的
    3. await关键字可是暂停异步函数向下执行 直到promise返回结果
    // 1. 在普通函数定义的前面加上async关键字 普通函数就变成了异步函数
    // 2. 异步函数默认的返回值使promise对象
    // 3. 在异步函数内保护使用throw关键字进行错误抛出
    
    
    
    // 4. await关键字
    // 它只能出现在异步函数中
    // awite后面跟promise对象 它可以暂停异步函数的执行,等待promise对象返回后再向下执行函数
    
    // async function fn() {
    //     throw '发生了一些错误';
    //     return 123;
    // }
    // // console.log(fn());
    // fn().then(function(data) {
    //         console.log(data);
    //     })
    //     .catch(function(err) {
    //         console.log(err);
    //     })
    
    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);
    }
    run();
    
    const fs = require('fs');
    
    const promisify = require('util').promisify;
    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);
    }
    run();
    

    4.9 Node.js全局对象global

    在浏览器中全局对象是window, 在Node中全局对象是global。

    Node中全局对象有以下方法, 在任何地方使用, global可以省略。

      1. console.log(); 在控制台中输出
      1. setTimeout() 设置超时定时器
      1. clearTimeout() 清除超时时定时器
      1. setInterval() 设置间歇定时器
      1. clearInterval() 清除间歇定时器
  • 相关阅读:
    109 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 05 问题解析--通过一个方法完成学生和专业的双向关联
    108 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 04 问题解析--数组未实例化造成的空指针异常
    107 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 03 编写方法完成学生个数统计功能
    106 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 02 新增属性完成学生信息存储
    105 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 01 新增需求及分析
    session与cookie的区别和联系
    session和cookie的区别
    Web服务器主动推送技术
    webSocket的场景应用
    TCP、Http和Socket 优劣比较
  • 原文地址:https://www.cnblogs.com/counter/p/14669483.html
Copyright © 2011-2022 走看看