• Node开发--->7_服务器端开发


    4 HTTP请求与相应处理

    4.1 请求参数

    用户名和密码需要通过某种形式(请求参数)传递到服务器端,服务器端要获取内容,用于后面的验证。
    请求参数分为get请求参数和post请求参数

    4.2 get请求参数

    发送请求

    • app.js
    const http = require('http');
    const app = http.createServer();
    
    app.on('request', (req, res) => { 
        res.writeHead(200, {
            'content-type': 'text/html;charset=utf8' 
        });
        console.log(req.url);
    
        if (req.url == '/index' || req.url == '/') { //错误写法req.url == '/index' ||  '/'
            res.end('<h2>欢迎来到主页</h2>');
        } else if (req.url == '/list') {
            res.end('welcome to list page');
        } else {
            res.end('not found');
        }
        if (req.method == 'POST') {
            res.end('post');
        } else if (req.method == 'GET') {
            res.end('get');
        }
    });
    app.listen(3000); 
    console.log('网站服务器启动成功');
    
    • 打开服务器,在浏览器中输入http://localhost:3000/index?name=zhangsan&age=20

    下面考虑在服务器端如何获取请求参数:在nodejs中提供了url内置模块,可以用于提取/index?name=zhangsan&age=20中的参数

    (1)第一步

    • app.js
    const http = require('http');
    const app = http.createServer();
    //用于处理url地址
    const url = require('url');
    
    app.on('request', (req, res) => { 
        res.writeHead(200, {
            'content-type': 'text/html;charset=utf8' //返回纯文本,若不指定这一项也是默认返回纯文本
        });
        //服务器端获取请求参数
        console.log(req.url);
        // url.parse(req.url); //parse:解析。  该方法返回一个对象
        console.log(url.parse(req.url));
    
        if (req.url == '/index' || req.url == '/') { //错误写法req.url == '/index' ||  '/'
            res.end('<h2>欢迎来到主页</h2>');
        } else if (req.url == '/list') {
            res.end('welcome to list page');
        } else {
            res.end('not found');
        }
        if (req.method == 'POST') {
            res.end('post');
        } else if (req.method == 'GET') {
            res.end('get');
        }
    });
    app.listen(3000);
    console.log('网站服务器启动成功');
    
    • 打开服务器,在浏览器中输入http://localhost:3000/index?name=zhangsan&age=20


      (2)第二步
    • 继续修改app.js将要查询的参数解析成对象的形式
      将以下代码
    console.log(url.parse(req.url));
    

    修改为(添加第二个参数)

    //参数1:要解析的url地址
    //参数2:将要查询的参数解析成对象的形式
    // url.parse(req.url,true); 
    console.log(url.parse(req.url, true));
    

    再刷新浏览器后:

    (3)第三步
    继续修改app.js拿到具体的请求参数
    将以下代码

    //参数1:要解析的url地址
    //参数2:将要查询的参数解析成对象的形式
    // url.parse(req.url,true); 
    console.log(url.parse(req.url, true));
    

    修改为

    //参数1:要解析的url地址false
    //参数2:将要查询的参数解析成对象的形式
    // url.parse(req.url,true); 
    let params = url.parse(req.url, true).query;
    console.log(params.name);
    console.log(params.age);
    

    再刷新浏览器后:

    解决not found问题

    添加请求参数后,判断失效。因为req.url里面既包含了请求地址又包含了请求参数,所以就不可以直接用url来判断
    (1)修改app.js
    将以下代码

    let params = url.parse(req.url, true).query;
    console.log(params.name);
    console.log(params.age);
    
    if (req.url == '/index' || req.url == '/') { //错误写法req.url == '/index' ||  '/'
        res.end('<h2>欢迎来到主页</h2>');
    } else if (req.url == '/list') {
        res.end('welcome to list page');
    } else {
        res.end('not found');
    }
    if (req.method == 'POST') {
        res.end('post');
    } else if (req.method == 'GET') {
        res.end('get');
    }
    

    修改为:

    //解构对象
    let { query, pathname } = url.parse(req.url, true)
    console.log(query.name);
    console.log(query.age);
    
    if (pathname == '/index' || pathname == '/') { //错误写法req.url == '/index' ||  '/'
        res.end('<h2>欢迎来到主页</h2>');
    } else if (pathname == '/list') {
        res.end('welcome to list page');
    } else {
        res.end('not found');
    }
    

    (2)开启服务器,刷新浏览器不再显示not found

    4.3 post请求参数

    1 客户端发送请求参数到服务器端

    • 在之前的form.js文件中进行编辑
    <body>
        <!-- 
        表单中的属性
        method:指定当前表单提交的方式,可以是GET也可以是POST,默认GET
        action:指定当前表单提交的地址
     -->
        <form action="http://localhost:3000" method="POST">
            <input type="text" name="username">
            <input type="password" name="password">
            <input type="submit">
        </form>
    </body>
    
    • 注意:
      在用户点击提交按钮的时候,希望把用户名和密码提交到服务器端,服务器如何接收参数呢?
      答:和get一样服务器通过参数的名字name来接收,所以每个表单项都需要一个名字,服务器根据这些名字来获取表单项,input中的name属性就是用来指定当前表单项的名字的。
    • get请求,请求参数是放在地址栏中传输的,post的请求参数在请求报文中,在服务器关闭的情况下,在浏览器中打开form.js,输入用户名和密码提交,停止加载页面后

    浏览器为了让我们更好地观察post参数,实际上对post参数做了显示上的优化,无论是post参数还是get参数,它们的格式都是一样的,点击Form Data右边的view source,可以看到

    2 如何在服务器端接收请求参数

    • 在sever文件夹下新建post.js,由于post参数没有存放在地址栏中,所以没有办法通过req.url来获取,post参数是通过事件(data、end)的方式来接收的。
    • post参数在理论上数据量可以是无限的,作为服务器而言,为了减轻压力,服务器对于post参数不是一次就接收完,比如传输一个100M的数据,服务器会分10次接收,每一次只会接收10M.当有请求参数传输的时候就会触发data事件,当请求参数传递完成后就会触发end事件
    • post.js
    //用于创建网站服务器模块
    const http = require('http');
    //返回值app就是网站服务器对象
    const app = http.createServer();
    
    app.on('request', (req, res) => {
        //post参数是通过事件的方式接收的
        //data事件:请求参数传递时触发
        //end事件:请求参数传递完成后触发
        //请求参数与请求相关,所以在req上绑定这两个事件
        //由于服务器不是一次性将post参数接收完成,所以先要声明一个变量postParams,然后在触发data事件时,要将当前传递过来的参数params和声明的变量进行拼接,之后在end事件触发的时候,输出变量postParams
        let postParams = '';
        req.on('data', params => { //params是传递过来的参数
            postParams += params;
        });
        req.on('end', () => {
            console.log(postParams);
        });
        //客户端的每次请求,服务器端都要作出相应,否则客户端将一直处于等待的状态
        //服务器端的相应内容如下:
        res.end('ok');
    });
    
    app.listen(3000);
    console.log('网站服务器启动成功');
    
    • 打开服务器

    • 浏览器中打开form.js,属于用户名和密码后提交,并在控制台中查看结果

    • 虽然获取到了参数,但是依然是字符串的形式,下面要对字符串username=ithema&password=123做处理,就要用到nodejs中的querystring模块,修改form.js如下

    //用于创建网站服务器模块
    const http = require('http');
    //返回值app就是网站服务器对象
    const app = http.createServer();
    //处理请求参数模块
    const querystring = require('querystring');
    
    app.on('request', (req, res) => {
        let postParams = '';
        req.on('data', params => { //params是传递过来的参数
            postParams += params;
        });
        req.on('end', () => {
            console.log(querystring.parse(postParams));
        });
        //客户端的每次请求,服务器端都要作出相应,否则客户端将一直处于等待的状态
        //服务器端的相应内容如下:
        res.end('ok');
    });
    
    app.listen(3000);
    console.log('网站服务器启动成功');
    
    • 重复上述过程

    3 小结

    请求体就是指请求报文

    4.4 路由

    在网站应用中有一个路由的概念,通过路由就可以完成上述网站的访问


    而上述代码缺少对请求方式的判断,同一个请求地址,如果请求方式不同,也要执行不同的处理逻辑。什么样的请求地址对应什么样的处理逻辑都是由开发人员决定的。

    • 在lesson2目录下新建文件夹route,route文件夹下新建app.js
    //1. 引入系统模块http
    const http = require('http');
    const url = require('url');
    //2. 创建网站服务器
    const app = http.createServer();
    //3. 为网站服务器对象添加请求事件
    app.on('request', (req, res) => {
        //4. 实现路由功能
        //(1)获取客户端的请求方式
        const method = req.method.toLowerCase(); //req.method通常返回大写的GET或者POST,做判断的时候为了方便通常会转化为小写
        //(2)获取客户端的请求地址
        const pathname = url.parse(req.url).pathname;
        //(3)逻辑处理s
        res.writeHead(200, {
            'content-type': 'text/html;charset=utf8'
        });
        if (method == 'get') {
            if (pathname == '/' || pathname == '/index') {
                res.end('欢迎来到首页');
            } else if (pathname == '/list') {
                res.end('欢迎来到列表页');
            } else {
                res.end('您访问的页面不存在');
            }
    
        } else if (method == 'post') {
    
        }
    });
    //5. 监听端口
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 打开服务器

    • 在浏览器中访问

    4.5 静态资源

    服务器端不需要处理,直接响应给客户端的资源就是静态资源,例如cssjsimagehtml文件。即浏览器可以直接运行的文件。比如网址http://www.itcast.cn/images/logo.png,请求的就是一张图片,服务器在接收到这个请求之后只需要找到这个图片,并将其直接响应给客户端。这个图片就是静态资源,无论谁来访问这个网址,得到的结果都是一样的。

    静态资源访问功能:在服务器端创建一个专门的文件夹,用于放置这些静态资源,当客户端请求某个静态资源文件的时候

    • 在lesson2目录下新建文件夹static,在static文件夹下新建文件夹public,在public中放置静态资源文件(提前准备好)
    • 在static文件夹下新建app.js文件,要在这个文件创建网址服务器并实现静态资源访问的功能
    //1. 引入系统模块http
    const http = require('http');
    const url = require('url');
    //2. 创建网站服务器
    const app = http.createServer();
    //3. 为网站服务器对象添加请求事件
    app.on('request', (req, res) => {
        res.end('ok');
    });
    //5. 监听端口
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 启动服务器

    • 访问静态资源
      错误的访问方法:http://localhost:3000/public/default.html
      原因:地址栏中的请求地址仅仅是一个字符串标识,仅仅是看起来像一个路径,也就是说上述public/default.html可以和服务器的真实路径是不一样的
      目标:希望用户输入http://localhost:3000/default.html就可以访问到default.html(不需要public)

    • 修改app.js

    const http = require('http');
    const url = require('url');
    const path = require('path');
    const fs = require('fs');
    const app = http.createServer();
    app.on('request', (req, res) => {
        //获取用户不含请求参数的请求路径
        let pathname = url.parse(req.url).pathname; //  得到/default.html
        //将用户的请求路径转换成实际的服务器硬盘路径
        //app.js文件的绝对路径__dirname
        // res.end(path.join(__dirname, 'public', pathname)); //E:Web13_Nodejslesson2staticpublicpublicdefault.html
        let realPath = path.join(__dirname, 'public', pathname);
        //根据真实路径读取文件
        fs.readFile(realPath, (error, result) => {
            //如果文件读取失败
            if (error != null) {
                res.writeHead(404, {
                    'content-type': 'text/html;charset=utf8'
                });
                res.end('文件读取失败');
                return;
            }
            res.end(result);
        });
    });
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 刷新浏览器

    静态资源访问功能的优化


    希望在上述情况下也访问default.html

    • app.js修改
    const http = require('http');
    const url = require('url');
    const path = require('path');
    const fs = require('fs');
    const app = http.createServer();
    app.on('request', (req, res) => {
        let pathname = url.parse(req.url).pathname; 
        //新增一行代码如下:
        pathname = pathname == '/' ? 'default.html' : pathname;
        let realPath = path.join(__dirname, 'public', pathname);
        fs.readFile(realPath, (error, result) => {
            if (error != null) {
                res.writeHead(404, {
                    'content-type': 'text/html;charset=utf8'
                });
                res.end('文件读取失败');
                return;
            }
            res.end(result);
        });
    });
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 刷新浏览器

    静态资源访问功能的优化2

    当服务器端为客户端作出相应的时候,要告知客户端当前给你的资源类型是什么。那么就有一个小问题,当浏览器拿到服务器发来的html代码的时候,浏览器要执行代码,但是在执行的过程中会遇到link标签、img标签、script标签等,这些标签可以去外链一些文件,但是目前只是请求了html文件(地址栏中输入http://localhost:3000/default.html)。当浏览器执行html代码遇到link标签、img标签、script标签中的需要外链文件的代码时,浏览器会自动向服务器发送请求。无论请求的是什么文件服务器都是通过fs.readFile来读取文件的,那么当前的一次读取有可能是html文件,有可能是css等,那么'content-type'应该如何写类型呢?(程序运行的过程中,我们不知道当前请求的是什么文件,所以这个值无法写成固定的,text/html? text/css?)
    答案:这就需要用到第三方模块mime。该模块可以根据当前的请求路径,分析出这个资源的类型。

    • 下载该模块
    • 开启服务器
    • app.js
    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; //  得到/default.html
        pathname = pathname == '/' ? 'default.html' : pathname;
        let realPath = path.join(__dirname, 'public', pathname);
        //根据路径返回文件类型
        let type = mime.getType(realPath);
        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.6 动态资源

    相同的请求地址可以传递不同的请求参数,得到不同的响应结果,这个响应结果就是动态资源,服务器将这个静态资源文件直接响应给客户端

    比如上述两个请求地址,它们的请求地址一样,但是传递了不同的请求参数,那么得到的结果就是不一样的。

  • 相关阅读:
    [Oracle DBA学习笔记] STARTUP详解
    亦步亦趋完成在CentOS 6.4下安装Oracle 11gR2
    ‘程序员’与‘页面仔’
    Linux下建立Oracle服务及其开机自启动
    解析并验证IE6及之前版本的'!important’ BUG
    浅谈CSS选择器中的空格
    在CentOS安装CMake
    关于CentOS下RPM的一些实例
    CentOS配置ssh无密码登录的注意点
    CentOS下的账户管理
  • 原文地址:https://www.cnblogs.com/deer-cen/p/12546799.html
Copyright © 2020-2023  润新知