W1_Express

Express:第三方模块

安装:npm install express
使用:
const express=require('express')
//创建一个http服务器
const app=express()

//静态资源服务器
app.use(express.static('./'))

const middleware=function(req,res,next){
	//req:request对象
	//res:response对象
	//next:是一个函数,用于执行下一个中间件
	console.log('hello middleware')
	//res.end(JSON.stringify(a:10,b:20))
	res.send({a:10,b:20}) //send里面可以写任何类型数据
}

//监听端口
app.listen(2101.()=>{
	console.log('server is running at port 2101')
})

Express中间件(middleware)

中间件是一个封装了某些处理数据功能的函数
使用中间件:use()里面可以使用多个中间件
app.use([path],...middlewares)

  • 分类:
    • 内置中间件:express自带的中间件
      • express.static()它的返回值是一个中间件
      • express.Router( )
      • express.urlencoded( )
      • express.json( )
    • 自定义中间件
      • 参数:(req,res,next)=>{ }
    • 第三方中间件
浏览器缓存
  • 强制缓存:状态码200 from cache
    • 缓存时间未过期,浏览器直接从本地获取
  • 协商缓存:状态码304
    • 缓存时间已过,浏览器发送请求到服务器进行询问,如果服务器的文件没有修改,则返回304,浏览器直接从本地获取(如果服务器文件有修改,服务器返回新的文件,状态码为200
RESTful规范

要求使用不同的请求类型事项相应的接口功能

  • 请求类型
    • get 查
    • post 增
    • put 改(全改)
    • patch 改(部分修改)
    • delete 删
const express = require('express')

// 创建一个路由中间件
const router = express.Router();


let goodslist = [];
for(let i=0;i<100;i++){
    const goods = {
        id:i+1,
        name:'goods'+i,
        price:(Math.random()*1000).toFixed(2),
        imgurl:'img/goods'+i+'.jpg'
    }
    goodslist.push(goods)
}
// 获取所有商品
// /goods
router.get('/',(req,res)=>{
    console.log('goodslist=',req.query);
    const {page=1,size=10} = req.query;

    // [0,1,2,3,...99]
    // page     index
    // 1        0
    // 2        10
    // 3        20
    // 推导公式: index = (page-1)*size
    const index = (page-1)*size;
    const end = index+size*1;
    const result = goodslist.slice(index,end);
    
    res.send(result)
});
// 获取指定id的商品
// /goods/10
router.get('/:id',(req,res)=>{
    // req.params = {id,a}
    // 获取动态路由参数
    const {id} = req.params;

    // const goods = goodslist.filter(item=>item.id==10)[0]
    const goods = goodslist.find(item=>item.id==id);
    res.send(goods)
});

router.delete('/:id',(req,res)=>{
    // 获取动态路由参数
    const {id} = req.params;

    // const goods = goodslist.filter(item=>item.id==10)[0]
    goodslist = goodslist.filter(item=>item.id!=id);
    res.send(`删除商品${id}成功`)
});

router.post('/',(req,res)=>{
    console.log('query=',req.query)
    console.log('body=',req.body)
    res.send('添加商品成功')
})

module.exports = router;
路由
  • 动态路由:req.params
  • url参数:req.query
  • 请求体:通过请求体发送的数据,必须通过对应的中间件处理
    • x-www-form-urlencode: express.urlencode()
    • json: express.json()

格式化请求体数据
router.use(express.urlencode( ),express.json( ) )

图片上传:multer
const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');

const router = express.Router();

// 1.简单上传:设置上传文件路径(目录不存在会自动创建)
// let uploadMiddleware = multer({ dest: '../public/uploads/avatar' })

// 2. 控制上传细节
// 配置上传参数
let storage = multer.diskStorage({
    destination: function (req, file, cb) {
        let uploadPath = `../public/uploads/${file.fieldname}`
        // 如路径不存在,则自动创建
        try{
            fs.accessSync(uploadPath)
        }catch(err){
            fs.mkdirSync(uploadPath,{
                recursive:true //递归
            })
        }

        cb(null, uploadPath);
    },

    // 上传文件保存目录,只有一层目录时可自动创建
    // destination:'../public/uploads/avatar',

    // 格式化文件名
    filename: function (req, file, cb) {
        console.log('file=',file);
        // 获取文件后缀名
        let ext = path.extname(file.originalname);

        cb(null, file.fieldname + '-' + Date.now() + ext);
    }
})

// 设置文件保存目录
let uploadMiddleware = multer({
    storage,
    fileFilter(req, file, cb){
        let ext = path.extname(file.originalname);
        const allow = ['.png','.gif','.jpg'].includes(ext);
        cb(null,allow)
    },
    limits:{
        fileSize:1024*1024*2
    }
});

// /api/upload/avatar
router.post('/avatar',uploadMiddleware.single('avatar'),(req,res)=>{
    // multer.single()中间件会把请求体中文件格式化到req.file属性
    console.log('file=',req.file);
    res.send('头像上传成功')
})

// /api/upload/goods
router.post('/goods',uploadMiddleware.array('goods',5),(req,res)=>{
    // multer.array()中间件会把请求体中文件格式化到req.files属性
    console.log('files=',req.files);
    console.log('body=',req.body);
    res.send('商品上传成功')
})

module.exports = router;
跨域解决方案
  • 跨域
    • 解决方案:
      • JSONP
      • CORS:cross origin resource sharing

        需要目标服务求授权(通过响应头)才能跨域访问数据

        • Access-Control-Allow-Origin
          • 单域名
          • *
        • Access-Control-Allow-Methods
        • Access-Control-Allow-Headers
      • 代理
        • http-proxy-middleware
解决方案之JSONP
	<h1>跨域解决方案之JSONP</h1>
    <button class="btnJsonp">jsonp</button>
    <script>
        // jsonp核心:
        // 1. 定义一个**全局函数**,用户接收数据并处理
        // 2. 传递**全局函数名**给后端
        (function(){
            const btnJsonp = document.querySelector('.btnJsonp')
            window.getUser = function(data){
                console.log('data=',data);
                
                document.body.removeChild(script);
            }
            // getUser(data)
            let script
            btnJsonp.onclick = function (){
                script = document.createElement('script');
                script.src = 'http://localhost:2101/api/jsonp?callback=getUser';
        
                document.body.appendChild(script);
            }
        })()
    </script>
// 跨域解决方案之jsonp
router.get('/jsonp',(req,res)=>{
    // 接收全局函数名
    const {callback='getData'} = req.query;

    // 读取数据库
    let data = [{
        id:1,
        name:'goods1',
        price:998,
        imgurl:'img/goods1.jpg'
    },{
        id:2,
        name:'goods2',
        price:998,
        imgurl:'img/goods2.jpg'
    },{
        id:3,
        name:'goods3',
        price:998,
        imgurl:'img/goods3.jpg'
    }]
    res.send(`${callback}(${JSON.stringify(data)})`)
})
跨域解决方案之CORS
    <h1>跨域解决方案之CORS</h1>
    <script>
        const xhr = new XMLHttpRequest
        xhr.onload = function(){
            console.log('data=',xhr.responseText);
        }
        xhr.open('get','http://localhost:2101/api/goods',true)
        xhr.setRequestHeader('Token','xxxx')
        xhr.send()
    </script>
const allowOrigin = 'http://localhost:3000,http://localhost:8080'.split(',')
// 跨域解决方案之CORS
router.use('/cors',(req,res,next)=>{
    // 判断客户端访问的域名是否在allowOrigin中
    const currentOrigin = req.get('Origin');
    if(allowOrigin.includes(currentOrigin)){
        // res.header("Access-Control-Allow-Origin", currentOrigin);
        // res.header("Access-Control-Allow-Methods", "PUT,POST,GET,PATCH,DELETE,OPTIONS");
        // res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With,Token");

        res.set({
            "Access-Control-Allow-Origin": currentOrigin,
            "Access-Control-Allow-Methods": "PUT,POST,GET,PATCH,DELETE,OPTIONS",
            "Access-Control-Allow-Headers": "Content-Type,Content-Length, Authorization, Accept,X-Requested-With,Token"
        })

        // 处理预请求
        if(req.method=="OPTIONS") {
            res.sendStatus(200);/*让options请求快速返回*/
        } else{
            res.send('cors data')
            next();
        }
    }else{
        next();
    }
})
解决方案之服务器代理

安装引入http-proxy-middleware

    <h1>跨域解决方案之服务器代理</h1>
    <script>
        const xhr = new XMLHttpRequest
        xhr.onload = function(){
            console.log('data=',xhr.responseText);
        }
        // 直接请求目标服务器报跨域限制
        // xhr.open('get','https://offer.qfh5.cn/api/iq?sort=hot',true)
        // xhr.open('get','http://localhost:2101/api/proxy/iq?sort=hot',true)

        xhr.open('get','http://localhost:2101/api/proxy/company',true)
        xhr.send()
    </script>
// 跨域解决方案之服务器代理
// 目标地址:https://offer.qfh5.cn/api/iq?sort=hot
// 代理步骤
// 1. 请求:http://localhost:2101/api/proxy/iq?sort=hot
// 2. 改为目标服务器:https://offer.qfh5.cn/api/proxy/iq?sort=hot
// 3. 删除多余路径:https://offer.qfh5.cn/api/iq?sort=hot
const proxyMiddleware = createProxyMiddleware({
    // 目标服务器
    target: 'https://offer.qfh5.cn', 
    changeOrigin: true,
    pathRewrite:{
        '^/api/proxy':'/api'
    }
})
router.use('/proxy',proxyMiddleware);
页面渲染模式
  • 客户端渲染:BSR

    页面开始是空页面,通过 ajax请求数据到前端遍历生成html结构再渲染到页面

    • 优点:
      • 局部刷新
      • 用户体验
      • 用户交互
  • 服务器渲染:SSR

    页面结构和内容在服务器生成后再返回给前端渲染

    • 优点:
      • SEO搜索引擎优化
      • 速度较快
简单利用nodejs爬数据
const request = require('request');
const cheerio = require('cheerio');
const superagent = require('superagent')
const iconv = require('iconv-lite')
const fs = require('fs')
const path = require('path');

// request.get('http://localhost:2101/api/goodslist',(err,res,body)=>{
//     console.log('body=',body);

//     const $ = cheerio.load(body)

//     const goodslist = [];
//     $('.goodslist li').each((idx,el)=>{
//         const price = $(el).find('.price').text().match(/[\d\.]+/);
//         const goods = {
//             id:$(el).data('id'),
//             name:$(el).find('h4').text(),
//             price:price ? price[0] : 0,
//             imgurl:$(el).find('img').attr('src')
//         }

//         goodslist.push(goods);
//     });

//     console.log('goodslist=',goodslist);
// })

// superagent.get('https://www.wbiao.cn/search/share/list/?bCode=111&w=%E7%99%BE%E8%BE%BE%E7%BF%A1%E4%B8%BD&exposedFrom=1').then((body,a,b)=>{
//     console.log('body=',body,a,b)
// })

// https://www.converse.com.cn/men-sneakers/category.htm?iid=hpnvc06012015
request({
    url:'https://list.suning.com/0-20006-0.html?safp=d488778a.phone2018.103327226421.1&safc=cate.0.0&safpn=10003.00006',
    encoding: null,

},(err,res,body)=>{
    body = iconv.decode(body, 'utf-8');
    // console.log('body=',body);
    const $ = cheerio.load(body)
    const phone = []
//     $('.goodslist li').each((idx,el)=>{
//         const price = $(el).find('.price').text().match(/[\d\.]+/);
//         const goods = {
//             id:$(el).data('id'),
//             name:$(el).find('h4').text(),
//             price:price ? price[0] : 0,
//             imgurl:$(el).find('img').attr('src')
//         }

//         goodslist.push(goods);
//     });
    $('.general li').each((idx,el)=>{
        const $el = $(el);
        const $img = $el.find('img');
        const imgurl = 'http:'+$img.attr('src');
        // const price = $(el).find('.def-price').text().match(/[\d\.]+/);
        const price = $(el).find('.def-price').text();
        const goods = {

                        // id:$(el).data('id'),
                        imgurl:imgurl,
                        price:price ? price[0] : 0,
                        name:$(el).find('.title-selling-point a').text(),
                    }
        phone.push(goods);

        // 下载图片: request请求一个图片地址,得到一个文件流
        const filename = path.basename(imgurl);
        // 创建一个写入流
        const writerStream = fs.createWriteStream('../public/img/'+filename)
        request(imgurl).pipe(writerStream);
        const item = {
            name: $img.attr('alt'),
            imgurl:filename
        }

    })


    console.log('phone=',phone);
    // 存入json文件
    fs.writeFile('./mock/phone.json',JSON.stringify(phone),(err)=>{
        if(err){
            console.log('文件写入失败')
        }else{
            console.log('文件写入成功')
        }
    });
})



编写数据接口

在这里插入图片描述

server.js
const express = require('express')
const allRouter = require('./routers')
const app = express();

// 静态资源服务器
app.use(express.static('../public'))

// 数据接口
app.use('/api',allRouter)

const PORT = 2101;
app.listen(PORT,()=>{
    console.log(`server is running at port ${PORT}`)
})
index.js
const express = require('express');

const userRouter = require('./user')
const goodsRouter = require('./goods')
const regRouter = require('./reg')
const loginRouter = require('./login')

const multer = require('multer')
const formData = multer();
// formData.single()
// formData.array();
// formData.none();

const router = express.Router();

router.use(
    express.urlencoded({extended:true}),
    express.json(),
    express.raw(),

    // 格式化formData<文本类型数据>到req.body
    formData.none(),
)

router.use('/user',userRouter);
router.use('/goods',goodsRouter);
router.use('/reg',regRouter);
router.use('/login',loginRouter);


module.exports = router;
login.js
const express = require('express');

const router = express.Router();

// 登录
router.get('/',(req,res)=>{
    // 获取前端传入的用户名和密码,查询数据库是否能匹配
})

module.exports = router;
reg.js
const express = require('express');

const router = express.Router();

// 注册
router.post('/',(req,res)=>{
    
})

// 检测用户名是否存在
router.get('/check',(req,res)=>{

})

module.exports = router;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值