node:http协议、sql、接口

本文深入解析HTTP请求的工作原理,介绍了如何通过SQL进行分页查询,特别是关注了模糊搜索。还探讨了在Node.js中实现接口设计和数据库操作的例子。

node:http协议、sql、接口

万维网是由一系列相互连接的文档组成的。其中许多文档是超文本标记语言(HTML)文档。web浏览器从服务器请求这些文档,并将内容呈现出来。呈现的内容依赖于一组Cascanding样式表(CSS)规则,这些规则通常在单独的CSS文件中提供,如果没有提供样式文件,那么将使用浏览器的默认值。HTML文档包含网页的内容,CSS文件包含有关如何将网页呈现给用户的信息。

网络通信

  与互联网的通信是通过你的计算机上的网络连接实现的,每次你的计算机与互联网上的另一台计算机通信时,连接就会被建立。这里主要有两种类型的连接,传输控制协议(TCP)连接和用户数据报协议(UDP)连接。在大多数情况下,当为浏览器请求网页时,会使用TCP连接。TCP没有指定如何检索网页,TCP是一个低层次的协议,它只关心确保数据传输,而这是留给超文本传输协议(HTTP)的。HTTP提供了一组关于客户端应该如何从服务器请求网页的规则,并规定了服务器应该如何响应。

进一步了解HTTP请求

  所有的HTTP请求都是在客户端和服务器这两方之间进行的。客户机是发起对话的计算机,服务器是处理请求的计算机(在对话中可能有中间代理)。根据定义,每个请求都由客户机发起,并从输入资源的名称开始。资源的名称作为统一资源定位符(URL)提供,其中包含检索文档所需的所有信息。单独的URL不足以启动连接,因为网络连接需要一个互联网协议(IP)地址来创建连接。IP地址类似于因特网上某台计算机的电话号码。要从URL获取IP地址,在域命名服务(DNS)中查询域名(URL中用句号标点的部分)。域名命名服务就像互联网的电话簿,允许通过给定的名称检索IP地址。域名是IP地址的别名,让用户更方便地记住他们感兴趣的资源的地址。一旦找到了一个URL的IP地址,计算机就会建立一个连接,当这个连接建立后,HTTP请求就可以开始了。HTTP是一种无状态协议,这意味着它们在请求之间没有内存或状态。

  HTTP请求是按照HTTP格式设置的字符序列。下面显示了一个HTTP请求的示例。

GET /index.html HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
Host: www.example.com
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive

  该请求包含一个HTTP动词,GET请求的资源,/index.html以及使用的协议版本,HTTP/1.1。请求的其余部分不是必需的,但是会向服务器提供附加信息。假设请求成功,服务器将响应一个状态代码和请求的资源。HTTP请求的响应示例如下所示。

HTTP/1.1 200 OK
Date: Mon, 11 April 2016 22:38:34 GMT
Content-Type: text/html; charset=UTF-8
Content-Encoding: UTF-8
Content-Length: 99
Last-Modified: Mon, 11 April 2016 00:00:00 GMT
Server: Apache/2.4.20 (Unix) (Red-Hat/Linux)
Accept-Ranges: bytes
Connection: close


<html>
  <head>
    <title>An Example Page</title>
  </head>
  <body>
    Hello World!!!!
  </body>
</html>

  来自服务器的响应包含一些响应头信息,后面跟着请求的内容。请求的第一行的数字,200,是请求的HTTP状态码。状态码200表示请求成功。

  在HTTP中指定了许多不同类型的HTTP请求。我们将在本课程中遇到许多请求类型。下表概述了它们的用途。

介绍请求类型
GET方法意味着检索由请求URI标识的任何信息(以实体的形式)。如果请求URI指的是一个数据生成过程,则生成的数据应该作为响应中的实体返回,而不是进程的源文本,除非该文本恰好是进程的输出。GET
POST方法用于请求源服务器接受包含在请求中的实体,作为请求行中由请求URI标识的资源的新下级。POST旨在采用统一的方法涵盖以下功能:1.对现有资源的注释;2.将消息发布到公告栏、新闻组、邮件列表或类似的文章组;3.向数据处理过程提供数据块,例如提交表单的结果;4.通过追加操作扩展数据库。POST
PUT方法请求将封闭的实体存储在提供的请求URI下。如果请求URI引用的是一个已经存在的资源,那么封闭的实体应该被认为是驻留在原始服务器上的实体的修改版本。如果请求URI不指向现有资源,并且该URI能够被请求用户代理定义为新资源,则源服务器可以使用该URI创建资源。PUT
DELETE方法请求源服务器删除由请求URI标识的资源。DELETE
HEAD方法与GET相同,只是服务器不能在响应中返回消息体。HEAD
TRACE方法用于返回远程、应用程序层的请求消息内容。TRACE
OPTIONS方法表示请求,以获取有关由请求URI标识的请求/响应链上可用的通信选项的信息。该方法允许客户端确定与资源或服务器功能相关的选项和/或需求,而不需要进行资源操作或启动资源检索。OPTION
此规范保留方法名CONNECT,以便与可以动态切换路径的代理一起使用。CONNECT
PATCH方法请求将请求实体中描述的一组更改应用于由请求URI标识的资源。PATCH

  HTTP状态码在决定请求是否成功时非常重要。下表总结了HTTP状态代码,完整的列表可以在Web技术学习资源介绍中找到。

状态码(以数字开头的)含义
1xx响应信息
2xx成功响应
3xx重定向响应
4xx客户端错误响应
5xx服务器错误响应

sql

查询
select * from jd_user 查询jd_user表的数据
select * from jd_user where account="admin" and password="admin@123" 有条件查询
添加

insert into jd_user(account, password, real_name, reg_time) VALUES ("xxxxx", "11111", "yyyyy", now())

更新(一定要加上约束条件)

update jd_user set account='aaaaaa' where id=5

删除(一定要加上约束条件)

delete from jd_user where id=5

用户接口

添加router.route('/user/create').post(userCtrl.createUser);
修改router.route('/user/update').post(userCtrl.updateUser);
删除router.route('/user/delete/:id').post(userCtrl.deleteUser);
查询router.route('/user/query').get(userCtrl.query);

分页接口(模糊)

  • 输入参数:pageNo页码(从第1页开始),pageSize当前页条数(一页显示20条)
  • 输出参数:list(20条) rows总条数 分页页码=math.ceil(rows/pageSize)
  • 模糊查询 模糊匹配
  • select * from jd_user where account like '%test%'
  • 查找account字段中包括test字符串的所有数据

表关联

  • 用户表 角色表 用户–角色表
  • 若需要查询某个用户有什么角色?
  • 一个用户可能有多个角色 一个角色可能被多个用户使用
select u.account,u.`password`, r.role_name
from jd_user u 
left join jd_user_role ur on u.id=ur.user_id
left join jd_role r on r.id = ur.role_id

表关联关系 left join xxx on xxx=xxxx

分页例子:

my.route.js

//路由
import express from 'express'
import userCtrl from '../controllers/user.ctrl'

const router = express.Router(); //使用express框架自带的路由 类比vue-router

export default function(app){
    //控制器接口--需要路由  接口请求方式(get post)
    //接口定义请求方式: get post delete put
    //用户        路由地址     请求方式   控制器接口
    router.route('/user/list-page').post(userCtrl.listPage);
    router.route('/user/create').post(userCtrl.createUser);
    router.route('/user/update').post(userCtrl.updateUser);
    router.route('/user/delete/:id').post(userCtrl.deleteUser);
    router.route('/user/query').get(userCtrl.query);
    router.route('/user/list').get(userCtrl.list);
    router.route('/user/login').post(userCtrl.login);// /api/user/login

    //权限

    //合同

    //把路由配置在myexpress实例上
    app.use('/api', router);
}

user.ctrl.js - 增删改查接口

//用户控制器 操作用户的接口
import logger from '../util/logger'
import * as userService from '../service/user.service'

const operations = {
    //用户查询
    query: function(req, res){
        logger.info("用户查询开始")
        userService.findUser("admin", "admin@123")
        .then(data=> {
            res.status(200).json(data)
            logger.info("用户查询结束")
        })
    },
    // 用户登录接口
    login: function(req, res){
        let {account, password} = req.body;
        logger.info("调用用户登录接口开始"+account+" "+password)
        userService.findUser(account, password)
        .then(data=> {
            if(data){
                let result = {
                    data:data,
                    token: new Date().getTime(),
                    msg: "用户登录成功"
                }
                res.status(200).json(result)
                logger.info("用户登录成功")
            }else{
                res.status(400).json({"msg":"用户登录失败"})
                logger.info("用户登录失败")
            }
        })
    },
    // 用户查询列表接口
    list: function(req, res){//req--request  res-response
        logger.info("调用用户查询接口")
        let users = [{name:"小张"}, {name:"小王"}]
        //给浏览器返回数据
        // res.status(200).send(users)
        res.status(200).json(users)
        logger.info("调用用户查询接口结束")
    },
    listPage: function(req, res){
        let {pageNo, pageSize, account} = req.body;
        if (pageNo && pageSize) {
            pageNo = pageNo - 1; //页数是从1开始 数据库是从0开始
            userService.findUserByPage(pageNo, pageSize, account)
            .then(data=>{
                res.status(200).json(data)
            })
        }
    },
    // 添加用户
    createUser: function(req, res) {
        const user = req.body;
        logger.info("添加用户"+JSON.stringify(user))
        userService.createUser(user)
        .then(data=>{
            res.status(200).json({"msg":"添加用户成功"})
            logger.info("添加用户结束")
        })
        .catch(err=>{
            res.status(400).json({"msg":err})
            logger.info("添加用户异常")
        })
    },
    //修改用户
    updateUser: function(req, res){
        const user = req.body;
        logger.info("修改用户"+JSON.stringify(user))
        userService.updateUser(user)
        .then(data=>{
            res.status(200).json({"msg":"修改用户成功"})
            logger.info("修改用户结束")
        })
        .catch(err=>{
            res.status(400).json({"msg":err})
            logger.info("修改用户异常")
        })
    },
    //删除用户  id参数希望在url最后面 /:id
    deleteUser: function(req, res){
        const userId = req.params.id;
        logger.info("删除用户"+userId)
        userService.deleteUser(userId)
        .then(data=>{
            res.status(200).json({"msg":"删除用户成功"})
            logger.info("删除用户结束")
        })
        .catch(err=>{
            res.status(400).json({"msg":err})
            logger.info("删除用户异常")
        })
    }
}

export default operations

user.service.js

// 用户服务层
import logger from '../util/logger'
import models from '../models'  //  ./models等价于./models/index
const User = models.jd_user;

/*登录查询**/
export function findUser(account, pwd) {
    return User.findOne({ //User模型自带findOne
        where: {
            account: account,   //左边的名字对应user模型名  右边是参数 
            password: pwd
        }
    })  //findOne--User模型自带的
}

/**
 * 用户添加
 * 输入参数:user对象,包括用户的基本信息,不需要id, 会自动增加
 * 输出:无
 */
export function createUser(user){
    return User.create(user);  //创建
}

/**
 * 用户修改
 * 输入参数:user对象,包括用户的基本信息, 需要id
 */
export function updateUser(user){
    if (user && user.id) {
        return User.findByPk(user.id) //根据用户id查找
            .then(u=>{ //u===查找到的用户
                return u.update(user)  //把传入的user覆盖到数据库的u上面
            })
    } else {
        logger.error("参数错误:"+JSON.stringify(user))
    }
}

/**
 * 用户删除
 * 输入参数:id
 */
export function deleteUser(uid){
    return User.destroy({ //删除  方法在数据模型中定义
        where: {
            id:uid
        }
    })
}

/**
 * 用户分页
 * 输入参数:pageNo页码(从第1页开始),pageSize当前页条数(一页显示20条)
   输出参数:list(20条) rows总条数 分页页码=math.ceil(rows/pageSize)
   - account  模糊匹配
 */
export async function findUserByPage(pageNo, pageSize, account){
    let limit = pageSize; //读多少条
    let offset = pageNo*pageSize; //从哪一条开始读 数据库里是从0开始
    let result = {};
    if (account) {
        //模糊匹配分页结果
        var d = await models.sequelize
                .query(`select * from jd_user where account like ? limit ${offset},${limit}`,
                {replacements:['%'+account+'%'], model: User})  //用account替换?
        result.data = d;
        //模糊匹配分页总条数
        var dd = await models.sequelize
                 .query("select count(*) num from jd_user where account like ?",
                 {replacements:['%'+account+'%']})
        if (dd) {
            // if (dd[0] && dd[0].length>0)
            result.rows = dd[0][0].num; //sql结果是一个二维数组
            result.pages = Math.ceil(result.rows/pageSize)
        }
    } else {
        var d = await User.findAll({ //查询所有
            limit: Number(limit),   //数字转换
            offset: Number(offset),
            order: [
                ["id", "desc"]  //数据反过来排列
            ]
        })
        result.data = d;
        var dd = await models.sequelize
                 .query("select count(*) num from jd_user")
        if (dd) {
            // if (dd[0] && dd[0].length>0)
            result.rows = dd[0][0].num; //sql结果是一个二维数组
            result.pages = Math.ceil(result.rows/pageSize)
        }
    }
    return result;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值