zoukankan      html  css  js  c++  java
  • node.js小滴课程笔记

     中文文档:http://nodejs.cn/

    nodejs是javascript的运行环境

    node.js遵守common.js规范

    module.exports   用来导出   可以导出对象也可以导出变量

    每一个模块的作用域是独立的

    初始化node项目   npm init  -y

    在node下那个木中定义全局变量用 global.变量=值;

    在其它模块可以直接使用   变量

    require用来导入模块

     Buffer缓冲器,用来处理二进制

    常用api:

    Buffer.alloc(10)创建一个长度为10的buffer

    Buffer.from([1,2,3]) 将数组[1,2,3]转换成Buffer

    Buffer.byteLength(Buffer.from([1,2,3]))buffer的长度

    Buffer.isBuffer(Buffer.from([1,2,3]))是否是buffer

    Buffer.concat([buf1,buf2])合并buffer    第二个参数可以指定长度   长的截取  短的填充

    const buf = Buffer.allocUnsafe(20)  创建一个不安全(可以修改的 buffer)
    buf.write("buffer",5,3)   将字符串 从下表为5的位子写入buffer,并且写入字符串的前3个字符    (最后面还可以有一个参数,就是字符编码,默认是utf8)
    buf.fill("eric",5,10)  填充buffer,把字符串或其它值,填充进去,填充位置是索引5-10   (最后一个参数也可以指定字符编码)
    buf.length   返回buffer的长度
    buf.toString()   将buffer对象转换为 字符串
    buf.toString('utf8',1,3)  将buffer对象的 1-2索引 解码成 utf8编码  并返回
     buf.toJSON()  将buf对象 转换为json对象格式
     buf1.equals(buf2)   对比两个buffer对象 是否相同
    buf1.indexOf('B')  查找字符在buffer的位置索引
    buf1.lastIndexOf('B')  查找字符在buffer的位置索引
    buf.slice(2,7)   截取buffer对象   [2,7)
    buf.copy(buf2)  将buf拷贝进buf2   还有第二个和第三个参数 和第四个参数 分别代表  从目标buffer的第几个索引开始放,将被拷贝buffer的索引几到索引几拷贝进去
    nodejs文件系统
    fs.readFile("文件路径",["utf8"],(err,data)=>{
      读取文件
    })
     
    fs.writeFile("./hello.text","this is a text2",["base64"],err =>{
        写入文件
    })
     
    fs.appendFile("./hello.text",Buffer.from("哈哈"),err=>{
        if(err) throw err;
        console.log("往文件追加内容成功");
    })
     
    fs.stat("./hello.text",(err,stats) => {
        if(err) throw {msg:"文件不存在"};
        console.log(stats);//文件信息
        console.log(stats.isFile());//是否为文件
        console.log(stats.isDirectory());//是否为文件夹
    })
     
    fs.rename("./hello.text","./test.text",err=>{//将hello.text冲命名成test.text
        if(err) throw {msg:"重命名失败"};
        console.log("重命名成功");
    })
     
    fs.unlink("./test.text",err=>{
        if(err) throw err;
        console.log("文件删除成功");
    })
     
    fs.mkdir("./a",err=>{//默认非递归创建  也就是不能嵌套创建文件夹  存在的文件夹也不能再创建
        if(err) throw err;
        console.log("文件夹创建成功")
    })

    fs.mkdir("./b/c",{recursive:true},err=>{//递归创建  可以在没有b文件夹的情况下  直接创建b文件夹嵌套c文件夹的形式
        if(err) throw err;
        console.log("文件夹递归创建成功")
    })
     
    fs.readdir("./",(err,files) => {//读取当前目录的所有文件列表
        if(err) throw err;
        console.log(files)
    })

    fs.readdir("./",{withFileTypes:true,encoding:"utf8"},(err,files) => {//读取当前目录的所有文件列表 列表中每一项都带上文件的类型
        if(err) throw err;
        console.log(files)
    })
     
    fs.rmdir("./a",err=>{//默认不能递归删除
        if(err) throw err;
        console.log("删除文件夹成功")
    })

    fs.rmdir("./b",{recursive:true},err=>{//递归删除文件夹  没有此文件夹不会报错
        if(err) throw err;
        console.log("递归删除文件夹成功")
    })
     
    fs.watch("./",(eventType,filename) => {//监听当前目录列表中 文件的变化 eventType:rename、change  通常用于本地构建
        console.log("发生改变的类型:" + eventType);
        console.log("文件【"+ filename+"】发生改变");
    })
     
    fs.watch("./",{//watch监听文件发生变化时,老是执行两次回调函数,所以我们再尝试一下下面的监听文件发生改变的方法
        recursive:true
    },(eventType,filename) => {//可以监听到子目录的变化
        console.log("发生改变的类型:" + eventType);
        console.log("文件【"+ filename+"】发生改变");
    })
     
     这里推荐使用一个插件:(避免监听 文件变化时,回调函数执行两次的情况)
    npm install chokidar --save-dev

    使用:

    const chokidar = require("chokidar");
    chokidar.watch("./").on("all",(event,path) => {//all代表 监听该目录下所有文件
        console.log(event+" --- "+path)
    })

    上面的监听发现,把当前文件夹下的node_modules文件都监听了,我们应该如何忽略呢?

    chokidar.watch("./",{//ignored  代表忽略的文件夹路径
        ignored:"./node_modules"
    }).on("all",(event,path) => {//all代表 监听该目录下所有文件 
        console.log(event+" --- "+path)
    })

     文件流:

    主要有:读取流和写入流,当然还有其他的分类

    下面来介绍一下读取流

    const fs = require("fs");
    
    let rs = fs.createReadStream('./streamTest.js',{
        highWaterMark:100,//这里指定每次获取100b的文件大小
    });//创建一个读取流 (读取自身)
    
    let count = 1;//这里做一个计数
    rs.on("data",chunk => {//读取每一块数据时的监听事件  默认每次读取64*1024b  也就是64kb的数据 流主要是通过buffer的形式传输的
        console.log(chunk.toString())
        console.log(count++);//每次读取完一段后 count计数自增1
    })
    
    rs.on("end",()=>{//监听读取结束事件
        console.log("读取完成")
    })

    下面来写一个  写入流的 例子:

    let ws = fs.createWriteStream("./a.txt");//创建一个写入流
    
    let num = 1;//创建一个计数
    
    let timer = setInterval(() => {
        if(num <= 10){
            ws.write(num + "");//将计数 写入  这里参数只能接受 字符串或者 buffer对象 所以转化成了字符串
            num++;//计数 自增1
        }else{
            ws.end("写入完成");//执行结束方法  结束方法也可以写入内容
            clearInterval(timer);//清除计时器
        }
    }, 200);
    
    ws.on("finish",()=>{//监听写入完成的事件
        console.log("写入完成")
    })
     管道流的使用方式,通常就是讲读取流 连接 到写入流‘
    let rs = fs.createReadStream("./streamTest.js");//创建一个读取流  读取当前文件
    let ws = fs.createWriteStream("./a.txt");//创建一个写入流  写入到当前目录下的a.txt下
    
    ws.on("finish",()=>{//这里加一个 写入流的监听事件
        console.log("写入完成")
    })
    // 利用管道 将读取流和写入流 连接到一起
    rs.pipe(ws);

     nodejs的path模块

    const {basename,dirname,extname,join,normalize,resolve,format,parse,sep,win32} = require("path");
    
    console.log(basename("/nodejs/2-6/index.js"));//返回最后一部分的内容  index.js
    console.log(basename("/nodejs/2-6/index.js",".js"));//返回最后一部分的内容 并且将后缀名去掉  index
    console.log(dirname("/nodejs/2-6/index.js"));//返回最后一部分内容所在的目录  /nodejs/2-6
    console.log(extname("index.js"));//返回文件后缀  .js
    
    console.log(join("nodejs","//seddir","index.js"));//拼接路径  nodejsseddirindex.js  并且我们如果多写了/ 他会自动修复 然后拼接
    console.log(normalize("/nodejs//seddir/index.js"));// 规范化路径 我们故意多加了一条/ 然后这个方法修复了 
    odejsseddirindex.js
    console.log(resolve("./pathTest.js"));//返回绝对路径  D:
    ode教程demo2-6pathTest.js
    
    let pathObj = parse("/nodejs/test/index.js");//解析路径成路径对象  parse和format是可以相互转化的
    console.log(pathObj);//{root: '/',dir: 'nodejs/test',base: 'index.js',ext: '.js',name: 'index'}
    console.log(format(pathObj));//   /nodejs/testindex.js
    console.log(sep);;//返回当前系统 路径分隔符    记住 他不是方法,是path上的属性  mac下应该是/
    console.log(win32.sep);//window系统下的 路径分隔符   
    
    // __filename :当前文件的 绝对路径   __dirname:当前文件的绝对目录  这两个api是node自带 不用专门引入
    console.log(__filename);//D:
    ode教程demo2-6pathTest.js   他和resolve有一定的区别  当执行文件不同时 resolve 的路径值得注意 它是相对于执行文件的绝对路径将文件名拼接到后面的 而__filename不会受执行文件的影响
    console.log(__dirname);// D:
    ode教程demo2-6>

     events事件触发器:大多数api都是基于事件触发器来触发的

     下面来 举个小例子:

    const EventEmitter = require("events");
    
    class MyEmitter extends EventEmitter{};//用es6的方式创建一个(事件触发器的)类 此类是通过继承EventEmitter类创建的
    
    let myEmitter = new MyEmitter();//这里创建一个(事件触发器的)实例
    
    myEmitter.on("hi",()=>{//在事件触发器实例上绑定一个事件  hi 
        console.log("hi事件触发了")
    })
    
    myEmitter.emit("hi");//通过这个事件触发器实例 的emit方法 触发 hi 事件

    那么如何传参呢? 回调函数和 emit参数中 第一个以后的参数 一一对应

    myEmitter.on("hi",(a,b)=>{
        console.log("hi事件触发了:"+ (a + b))
    })
    
    myEmitter.emit("hi",1,8);

    用once绑定的事件只能触发一次,多次触发 无效

    myEmitter.once("hello",()=>{//once绑定的事件 只能触发一次  多次触发不生效
        console.log("hello事件触发了")
    })
    
    myEmitter.emit("hello");
    监听器实例可以利用removeListener方法  移除指定事件中的回调函数:
     
    function fn1(a,b){//方法1
        console.log("hi事件触发了 事件带参:"+ (a + b))
    }
    
    function fn2(){//方法2
        console.log("hi事件触发了 事件不带参:")
    }
    myEmitter.on("hi",fn1);//给hi事件绑定上 fn1 方法
    myEmitter.on("hi",fn2);//再给hi事件绑定上 fn2 方法
    
    myEmitter.emit("hi",1,8);
    
    // 将fn2 冲hi事件中移除
    myEmitter.removeListener("hi",fn2);
    myEmitter.emit("hi",1,8);//再执行一次  此次只执行fn1回调了

     可以用监听器实例上的removeAllListeners方法,将指定事件上的方法全部移除:

    myEmitter.removeAllListeners("hi");
    myEmitter.emit("hi",1,8);//没执行任何 回调  因为都移除了

     核心模块util

     util的callbackify方法可以使async函数变成有回调风格的函数:

    const util = require("util");
    
    async function hello(){
        return "hello world";
    }
    
    let helloCb = util.callbackify(hello);//将hello方法  转换成有回调风格的 方法
    
    helloCb(((err,data) => {
        if(err) throw err;
        console.log(data);
    }))
    util.promisify  可以将回调风格的函数转化成promise风格的函数  避免回调地狱
    const util = require("util");
    const fs = require("fs");
    
    fs.stat("./utilTest.js",(err,data)=>{//fs.stat用来查看 文件信息 是一个回调风格的函数
        if(err) throw err;
        console.log(data)
    })
    
    let stat = util.promisify(fs.stat);//将回调风格的函数  转化成 promise风格的函数
    
    stat("./utilTest.js").then(data=>{
        console.log(data)
    }).catch(err=>{
        console.log("出错了");
        console.log(err)
    })

    当然也可以用async的方式来写

    const util = require("util");
    const fs = require("fs");
    
    let stat = util.promisify(fs.stat);//将回调风格的函数  转化成 promise风格的函数
    
    async function statFn(){
        try{
            let statInfo = await stat("./utilTest.js");
            console.log(statInfo)
        }catch(e){
            console.log(e);
        }
    }
    statFn()
    util.types.isDate() 判断是否为日期类型
    util.types.isDate(new Date);//判断是否为日期类型 true
    util.types.isDate("2020/06/22");//false

    当然还可以判断许多其它的,可以查文档

     http:HyperText transfer protocal  超文本传输协议
    客户端输入url,这个过程发生了什么事
    1、DNS解析:把域名解析成一个ip地址
    2、TCP连接:(三次握手)(1):客户端给服务端说,你好我要建立连接了(2)服务端收到后,回复客户端,好的,我们可以连接(3)客户端收到后,回复,那我们发送连接了,然后夫妇段就收到了连接。
    3、浏览器发送http请求
    4、服务端处理请求
    5、浏览器解析渲染页面
    6、连接结束(4次握手)
     http请求方法和响应头信息
    http请求方法
    GET:请求指定的页面信息,并返回实体主体
    HEAD:类似于GET请求,只不过返回的响应中没有具体的内容,用于获取报头
    POST:向指定资源提交数据进行处理请求,数据被包含在请求体中。
    PUT:从客户端向服务器传送的数据取代指定的相应的内容
    DELETE:请求服务器删除指定的页面
    CONNECT:http/1.1协议中预留给能够将链接改为管道方式的代理服务器
    OPTIONS:允许客户端查询服务器的性能
    TRACE:回显服务器收到的请求,主要用于测试或诊断
     
    http响应头信息
    Allow:服务器支持哪些请求方法(get、post等)
    Content-Encoding:文档的编码方法。只有在解码之后才可以得到Content-type头指定的内容类型。利用gzip压缩,能减少html文档的下载时间
    Content-Length:表示内容长度,只有当浏览器使用持久http连接时才需要这个数据
    Content-Type:表示文档属于什么MIME类型
    Date:当前GMT时间
    Expires:资源什么时候过期,不再缓存
    Last-Modified:文档最后改动时间
    Location:重定向的地址
    Server:服务器的名字
    Set-Cookie:设置和页面关联的cookie
    WWW-Authenticate:定义了使用何种验证方式去获取对资源的连接
     
    http状态码
    常见的http状态码:
    200:请求成功
    301:资源被永久转移到其它url
    404:请求资源(网页等)不存在
    500:内部服务器错误
    http状态码分为5类:
    1**:信息,服务器收到请求,需要请求者继续执行操作
    2**:操作被成功接收,并处理
    3**:重定向,需要进一步的操作并完成请求
    4**:客户端错误,请求包含语法错误或无法完成请求
    5**:服务器错误,服务器在处理请求的过程中发生了错误
    Content-Type:内容类型:
    text/html:HTML格式
    text/plain:纯文本格式
    text/XML:XML格式
    image/gif:gif图片格式
    image/jpeg:jpg图片格式
    image/png:png图片格式
    multipart/form-data:需要在表单中进行文件上传时,就需要使用该格式
    。以application开头的媒体格式类型
    application/xhtml+xml:XHTML格式
    application/xml:XML数据格式
    application/atom+xml:Atom + XML聚合类型
    application/json:json数据格式
    application/pdf:pdf格式
    application/msword:word文档格式
    application/octet-stream:二进制流数据(常见的文件下载)
    application/x-www-form-urlencoded:表单中默认的encType,表单数据被编码为key/value格式发送到服务器
     
    创建一个简单的服务器:
    const http = require("http")
    
    const server = http.createServer((req,res) => {
        res.writeHead(200,{'content-type':'text/html'});
        res.end('<h1>hello world</h1>');
        
    })
    
    server.listen(3000,()=>{
        console.log("监听了3000端口")
    })

     url.parse方法:用来解析路径

    下面举个小例子:

    const url = require("url")
    
    console.log(url.parse("https://api.xdclass.net/pub/api/v1/web/product/find_list_by_type?type=2"));
    Url {
      protocol: 'https:',
      slashes: true,
      auth: null,
      host: 'api.xdclass.net',
      port: null,
      hostname: 'api.xdclass.net',
      hash: null,
      search: '?type=2',
      query: 'type=2',
      pathname: '/pub/api/v1/web/product/find_list_by_type',
      path: '/pub/api/v1/web/product/find_list_by_type?type=2',
      href: 'https://api.xdclass.net/pub/api/v1/web/product/find_list_by_type?type=2'
    }
    //加上第二个参数  默认是false 设为true,会解析query参数
    console.log(url.parse("https://api.xdclass.net/pub/api/v1/web/product/find_list_by_type?type=2",true));
    Url {
      protocol: 'https:',
      slashes: true,
      auth: null,
      host: 'api.xdclass.net',
      port: null,
      hostname: 'api.xdclass.net',
      hash: null,
      search: '?type=2',
      query: [Object: null prototype] { type: '2' },
      pathname: '/pub/api/v1/web/product/find_list_by_type',
      path: '/pub/api/v1/web/product/find_list_by_type?type=2',
      href: 'https://api.xdclass.net/pub/api/v1/web/product/find_list_by_type?type=2'
    }

    如何处理get请求

    const url = require("url")
    const http = require("http")
    
    const server = http.createServer((req,res) => {
        // 创建一个对象,将请求的url解析后存起来
        let urlObj = url.parse(req.url,true);
        // 我们将query参数 返回到页面上
        res.end(JSON.stringify(urlObj.query))
    });
    
    server.listen(3000,() => {
        console.log("监听3000端口");
    })

     如何处理post请求

    const url = require("url")
    const http = require("http")
    
    const server = http.createServer((req,res) => {
        // 监听post请求,因为post请求 是以流的形式 传递参数,所以 需要不断的监听
        let postData = '';
        // 监听post请求的 数据 要用监听流的形式监听
        req.on("data",chunk => {
            //这里chunk本来是buffer对象  由于用了字符串拼接  所以 隐式的将buffer对象转换成了字符串类型
            postData += chunk;
        })
        // 监听传输结束事件
        req.on("end",()=>{
            console.log(postData);
        })
        // 返回
        res.end(JSON.stringify({
            data:"请求成功",
            code:0,
            
        }))
    });
    
    server.listen(3000,() => {
        console.log("监听3000端口");
    })

     整合get/post请求

    const url = require("url")
    const http = require("http")
    
    const server = http.createServer((req,res) => {
    
        if(req.method === 'GET'){
            let urlObj = url.parse(req.url,true);
            res.end(JSON.stringify(urlObj.query))
        }else if(req.method === 'POST'){
            let postData = '';
            req.on("data",chunk => {
                postData += chunk;
            })
            req.on("end",()=>{
                console.log(postData);
            })
            res.end(JSON.stringify({
                data:"请求成功",
                code:0,
                
            }))
        }    
    });
    
    server.listen(3000,() => {
        console.log("监听3000端口");
    })

    补充一下,post请求可以用postman发送,百度一下可以下载

     使用nodemon自动重启工具

    nodemon可以让node项目自动重启,我们之前改点代码,需要手动重启项目才能生效,nodemon工具可以在我们改动代码后自动重启。

    推荐全局安装:npm install -g nodemon

    比如说要启动 server.js   

    之前的启动是:node server

    那么用nodemon启动就是:nodemon server

    定义命令

    先初始化一下项目:npm init -y

    之后出现了package.json文件

    找到script字段,自定义一个命令

    "scripts": {
        "start":"nodemon reqTest.js"
      },

    然后我们就可以 通过 npm run start来启动项目了

    路由初始化以及接口开发

    我们先写个最原始的接口,通过请求的路径和请求方法来判定具体是哪一个接口

    server.js

    const http = require("http")
    const url = require("url")
    
    const server = http.createServer((req,res)=>{
        // 将返回类型变成json格式  编码为utf-8  防止中文乱码
        res.writeHead(200,{'content-type':'application/json;charset=UTF-8'});
        // 拿到路径参数
        let urlObj = url.parse(req.url,true);
        if(urlObj.pathname === '/api/aa' && req.method === 'GET'){
            //若路径名是/api/aa  并且是get请求  则返回query参数
            res.end(JSON.stringify(urlObj.query))
        }else{
            res.end('404 not found')
        }
    })
    
    server.listen(3000,()=>{
        console.log("服务启动 3000端口")
    })

    可以看到以上是写了一个接口,如果写很多个接口,都放到server.js文件中,那么这个文件就会显的臃肿,那么接下来我们就可以整合一下接口。

    创建一个router文件夹,创建index.js

    const url = require("url")
    function handleRequest(req,res){
        // 拿到路径参数
        let urlObj = url.parse(req.url,true);
        if(urlObj.pathname === '/api/aa' && req.method === 'GET'){
            //若路径名是/api/aa  并且是get请求  则返回query参数
            return{
                msg:"获取成功",
                code:0,
                data:urlObj.query
            }
        }
    
        if(urlObj.pathname === '/api/post' && req.method === 'POST'){
            //若路径名是/api/post  并且是post请求  
            return{
                msg:"获取成功",
                code:0,
            }
        }
    }
    
    module.exports = handleRequest;

    server.js对应改为:

    const http = require("http")
    const routerModal = require("./router/index");
    const server = http.createServer((req,res)=>{
        // 将返回类型变成json格式  编码为utf-8  防止中文乱码
        res.writeHead(200,{'content-type':'application/json;charset=UTF-8'});
        let resultData = routerModal(req,res);
        if(resultData){
            //如果resultData有数据  就把数据返回出去
            res.end(JSON.stringify(resultData));
        }else{
            res.writeHead(404,{'content-type':'text/html'})
            res.end('404 not found')
        }
        
    })
    
    server.listen(3000,()=>{
        console.log("服务启动 3000端口")
    })

     实战用户列表增删改查:(不过现在还没连接数据库,数据仍然是假的)

    很显然,我们需要些4个接口,用户列表获取、新增、删除、更新

    server.js:比之前多了个获取post数据的方法,自定义给req对象上加了个body属性,将post传来的数据赋值给了它

    const http = require("http")
    const routerModal = require("./router/index");
    const getPostData = function(req){
        //封装一个获取post的数据的方法
        return new Promise((resolve,reject) => {
            if(req.method !== 'POST'){
                //如果不是post请求 就返回个空对象
                resolve({});
                return;
            }
            let postData = '';
            req.on("data",chunk => {
                postData += chunk;
            })
            req.on("end",()=>{
                resolve(JSON.stringify(postData))
            })
        })
    }
    
    const server = http.createServer((req,res)=>{
        // 将返回类型变成json格式  编码为utf-8  防止中文乱码
        res.writeHead(200,{'content-type':'application/json;charset=UTF-8'});
        getPostData(req).then(data=>{//这里的data就是post请求传来的数据
            req.body = data;//自定义给req对象加一个body属性,将post传过来的数据赋值给body
            let resultData = routerModal(req,res);
            if(resultData){
                //如果resultData有数据  就把数据返回出去
                res.end(JSON.stringify(resultData));
            }else{
                res.writeHead(404,{'content-type':'text/html'})
                res.end('404 not found')
            }
        })
            
        
    })
    
    server.listen(3000,()=>{
        console.log("服务启动 3000端口")
    })

    router/index.js

    const url = require("url")
    const {getUserList,addUser,deleteUser,updateUser} = require("../controller/user")
    function handleRequest(req,res){
        // 拿到路径参数
        let urlObj = url.parse(req.url,true);
        if(urlObj.pathname === '/api/getUserList' && req.method === 'GET'){
            //获取用户列表接口
            let resultData = getUserList();
            return resultData;
        }
    
        if(urlObj.pathname === '/api/addUser' && req.method === 'POST'){
            //用户新增接口
            let resultData = addUser(req.body);
            return resultData;
        }
    
        if(urlObj.pathname === '/api/deleteUser' && req.method === 'POST'){
            //删除用户接口
            let resultData = deleteUser(urlObj.query.id);
            return resultData;
    
        }
    
        if(urlObj.pathname === '/api/updateUser' && req.method === 'POST'){
            //删除用户接口
            let resultData = updateUser(urlObj.query.id,req.body);
            return resultData;
    
        }
    }
    
    module.exports = handleRequest;

    controller/user.js:这一个文件专门是用来处理数据的,user.js是专门用来处理用户数据的,分好模块。现在是模拟数据,将来会从操作数据库

    module.exports = {
        getUserList(){
            //获取用户列表
            return [
                {id:1,name:"tom",city:"北京"},
                {id:2,name:"xiaoming",city:"广州"},
                {id:3,name:"xiaohua",city:"上海"},
            ]
        },
        addUser(userObj){
            // 新增用户
            console.log(userObj);
            return {
                code:0,
                msg:"新增成功",
                data:null
            }
        },
        deleteUser(id){
            //删除用户
            console.log(id)
            return {
                code:0,
                msg:"删除成功",
                data:null
            }
        },
        updateUser(id,userObj){
            //更新用户信息
            console.log(id,userObj);
            return {
                code:0,
                msg:"更新成功",
                data:null
            }
        }
    }

     解决接口跨域问题

    我们在项目中写个html页面,用jquey去请求我们之前写的接口:

    这里给大家推荐个vscode插件:live server  下载安装后,打开当前html文件,点击右下角GO live 就可以将当前html放到一个服务器上面运行,很方便‘

    我们在html发送了一条请求;

           $.ajax({
                url:"http://127.0.0.1:3000/api/getUserList",
                success:function(res){
                    console.log(res)
                }
    
            })

    然后报了跨域。

    如何解决跨域呢?

    我们只需要在服务器的响应对象上加上:这样所有不同的域就可以跨域请求了

    // 设置跨域处理
        res.setHeader("Access-Control-Allow-Origin","*");

     正常在服务器上是不会设置  *  号的,这样就相当于把接口共享了,一般会设置指定的可访问的地址

    // 设置跨域处理
    res.setHeader("Access-Control-Allow-Origin","http://127.0.0.1:5500");

     结合数据库改造用户列表接口  (增)

    数据库配置:

    config/db_config.js:

    let dbOption;
    
    dbOption = {
        connectionLimit:10,//同时创建连接的最大连接数
        host:"localhost",//连接地址
        user:"root",//用户
        password:"123456",//密码
        port:'3306',//端口
        database:"user_test",//要连接的数据库
    }
    
    module.exports = dbOption;

    数据库连接以及query方法封装:

    db/conn.js:

    const mysql = require("mysql")
    const dbOption = require("../config/db_config")
    
    // 创建连接池
    const pool = mysql.createPool(dbOption);
    
    // 封装一个 sql语句执行方法  因为这个执行方法有可能在很多文件重复调用 所以封装一下
    // 接受sql语句,以及参数
    function query(sql,params){
        return new Promise((resolve,reject) => {
            pool.getConnection((err,conn) => {
                if(err){
                    reject(err);
                    return;
                }
                // 执行sql语句
                conn.query(sql,params,(err,result) => {
                    // 不管是否 报错  首先将连接 释放掉
                    conn.release()
                    if(err){
                        reject(err);
                        return;
                    }
                    resolve(result);
                })
            })
        })
    }
    
    module.exports = query

    server.js:响应有点更改

    const http = require("http")
    const routerModal = require("./router/index");
    const getPostData = function(req){
        //封装一个获取post的数据的方法
        return new Promise((resolve,reject) => {
            if(req.method !== 'POST'){
                //如果不是post请求 就返回个空对象
                resolve({});
                return;
            }
            let postData = '';
            req.on("data",chunk => {
                postData += chunk;
            })
            req.on("end",()=>{
                resolve(JSON.parse(postData))
            })
        })
    }
    
    const server = http.createServer((req,res)=>{
        // 设置跨域处理
        res.setHeader("Access-Control-Allow-Origin","http://127.0.0.1:5500");
        // 将返回类型变成json格式  编码为utf-8  防止中文乱码
        res.writeHead(200,{'content-type':'application/json;charset=UTF-8'});
        getPostData(req).then(data=>{//这里的data就是post请求传来的数据
            req.body = data;//自定义给req对象加一个body属性,将post传过来的数据赋值给body
            let result = routerModal(req,res);
            if(result){
                result.then(resultData => {
                    //把数据返回出去
                    res.end(JSON.stringify(resultData));
                })
            }else{
                res.writeHead(404,{'content-type':'text/html'})
                res.end('404 not found')
            }
        })
            
        
    })
    
    server.listen(3000,()=>{
        console.log("服务启动 3000端口")
    })

    router/index.js:没有发生改变

    const url = require("url")
    const {getUserList,addUser,deleteUser,updateUser} = require("../controller/user")
    function handleRequest(req,res){
        // 拿到路径参数
        let urlObj = url.parse(req.url,true);
        if(urlObj.pathname === '/api/getUserList' && req.method === 'GET'){
            //获取用户列表接口
            let resultData = getUserList();
            return resultData;
        }
    
        if(urlObj.pathname === '/api/addUser' && req.method === 'POST'){
            //用户新增接口
            let resultData = addUser(req.body);
            console.log(resultData,"index.js")
            return resultData;
        }
    
        if(urlObj.pathname === '/api/deleteUser' && req.method === 'POST'){
            //删除用户接口
            let resultData = deleteUser(urlObj.query.id);
            return resultData;
    
        }
    
        if(urlObj.pathname === '/api/updateUser' && req.method === 'POST'){
            //删除用户接口
            let resultData = updateUser(urlObj.query.id,req.body);
            return resultData;
    
        }
    }
    
    module.exports = handleRequest;

    controller/user.js:的addUser方法发生了改变

    const query = require("../db/conn");
    module.exports = {
        getUserList(){
            //获取用户列表
            return [
                {id:1,name:"tom",city:"北京"},
                {id:2,name:"xiaoming",city:"广州"},
                {id:3,name:"xiaohua",city:"上海"},
            ]
        },
        async addUser(userObj){
            // 新增用户
            console.log(userObj);
            let {name,city,sex} = userObj;
            let sql = 'insert into user (name,city,sex) values (?,?,?)';
            let resultData = await query(sql,[name,city,sex]);
            console.log(resultData,"user.js");
            if(resultData){
                return {msg:"新增成功"}
            }else{
                return {msg:"新增失败"}
            }
        },
        deleteUser(id){
            //删除用户
            console.log(id)
            return {
                code:0,
                msg:"删除成功",
                data:null
            }
        },
        updateUser(id,userObj){
            //更新用户信息
            console.log(id,userObj);
            return {
                code:0,
                msg:"更新成功",
                data:null
            }
        }
    }

    目录结构:

     结合数据库改造用户列表接口:(查

    user.js:

    async getUserList(urlParams){
            let {name,city} = urlParams;
            let sql = 'select * from user where 1=1';
            if(name){
                sql += ' and name = ?';
            }
            if(city){
                sql += ' and city = ?';//注意前面流一个空格 要不查询数据库就会 报错 说太靠近了
            }
            console.log(sql);
            let resultData = await query(sql,[name,city]);
            //获取用户列表
            return resultData;
        },

    urlParams参数记得在index.js中传过来

    // 拿到路径参数
        let urlObj = url.parse(req.url,true);
        if(urlObj.pathname === '/api/getUserList' && req.method === 'GET'){
            //获取用户列表接口
            let resultData = getUserList(urlObj.query);
            return resultData;
        }

                                                                                                                                                                                                                                       

     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    反转句子
    算法和数据操作-查找和排序
    算法和数据操作-递归和循环
    数据结构-树
    数据结构-栈和队列
    Spring的循环依赖
    关于mybatis的执行流程和源码
    JVM之了解JVM的结构和加载机制
    多线程之(线程管理)
    Spring容器创建过程
  • 原文地址:https://www.cnblogs.com/fqh123/p/13089868.html
Copyright © 2011-2022 走看看