zoukankan      html  css  js  c++  java
  • webpack 配置react脚手架(六):api

    1 访问网址 https://cnodejs.org/api 可以调取api

    2.//该body-parser 可以将请求的body数据,转变成 json 格式数据;
    //express-session 用于在服务器端存放的session
    //query-string 用于转换 url 后面的请求参数 转换成 json 格式

    npm i body-parser express-session query-string -S

     bodyParser中间件的研究

    3 使用方法:

    3.1 server.js 主程序:

    const express = require('express')
    const ReactSSR = require('react-dom/server');
    
    const bodyParser = require('body-parser');//转换成json
    const session = require('express-session');//服务端保存数据
    
    const fs = require('fs')
    const path = require('path')
    const app = express();
    
    
    app.use(bodyParser.json());//把请求中的数据 转成 req.body 上的数据
    app.use(bodyParser.urlencoded({ extended:false})); //表单提交 转换成 req.body上的数据
    app.use(session({ //没有做数据库,放在了内存中
        maxAge:10*60*1000, //有效期
        name:'tid', //session 会给浏览器一个 cookie id
        resave:false, //每次请求是否申请一个cookie id
        saveUninitialized:false,
        secret:'react conde class' //加密
    }))
    
    app.use('/api/user',require('./util/handle-logim'));
    app.use('/api',require('./util/proxy'))
    
    
    const isDev = process.env.NODE_ENV === 'development'; 
    if(!isDev){
        const serverEntry = require('../dist/server-entry').default;
        const template = fs.readFileSync(path.join(__dirname, '../dist/index.html'), 'utf8')
        app.use('/public', express.static(path.join(__dirname, '../dist'))); 
        app.get('*', function (req, res) {
          const appString = ReactSSR.renderToString(serverEntry);
          res.send(template.replace('<!--app-->',appString)) 
        })    
    }else{
        const devStatic = require('./util/dev.static.js');
       devStatic(app); 
    
    app.listen(3333, function () {
      console.log('server is listening on 3333')
    })

    3.2 login的登陆逻辑:

    //login.js
    //因为要把登陆的信息放在服务器session中,不是直接的调取返回数据,所以要单独处理登陆接口
    const router = require('express').Router();
    const axios = require('axios');
    //文档定义 以下 api 路径均以 https://cnodejs.org/api/v1 为前缀
    const baseUrl = 'http://cnodejs.org/api/v1';
    // 文档中规定 post/accesstoken 验证 accessToken 的正确性;
    // 接受 post参数 accesstoken 用户的 accessToken
    router.post('/login',function(req,res){ //执行登陆接口
        axios.post(`${baseUrl}/accesstoken`,{ //post /accesstoken 验证 accessToken 的正确性 
            //接收 post 参数 -- accesstoken String 用户的 accessToken
            accesstoken:req.body.accessToken //把用户传递过来的 accesstoken 传给api;注意api中的 accesstoken 用的不是驼峰
        }).then(resp=>{
            if(resp.status == 200 && resp.data.success){
                //把登陆的信息保存到 session 中,下次请求的时候就可以通过 session 获取到
                req.session.user = { //在seesion上保存 user 的数据,其中 accessToken 是用户传递过来的所以可以直接使用
                    accessToken:req.body.accessToken,
                    loginName:resp.data.loginname, //loginname,id,vul等数据是返回来的
                    id:resp.data.id,
                    avatarUrl:resp.data.avatar_url
                }
                res.json({
                    success:true,
                    data:resp.data
                })
            }
        }).catch(err => {
            if (err.response) {
                res.json({
                    success:false,
                    data:err.response
                })
            }else{
                next(err)
            }
        })
    
    })
    
    module.exports = router;

    3.3 proxy.js

    //把用户请求数据的接口,全部代理出去
    const axios = require('axios')
    const querystring = require('query-string')
    
    const baseUrl = 'http://cnodejs.org/api/v1'
    
    module.exports = function (req, res, next) { //抛出一个函数 
      const path = req.path;
      const user = req.session.user || {} //判断用户有没有登陆
      const needAccessToken = req.query.needAccessToken //是否需要 accesstoken,请求参数 放在 url?后面
      //如果url中规定需要 token ,并且session中没有 token
      if (needAccessToken && !user.accessToken) {
        res.status(401).send({
          success: false,
          msg: 'need login'
        })
      }
    
      //不能直接使用query,比如url上可能携带,是否需要token的参数 needAccessToken;
      const query = Object.assign({}, req.query, {
        accesstoken: (needAccessToken && req.method === 'GET') ? user.accessToken : ''
      })
      if (query.needAccessToken) delete query.needAccessToken //如果有needToken 则删掉
    
      axios(`${baseUrl}${path}`, {
        method: req.method, // `method` 是创建请求时使用的方法,默认是 get
        params: query, // `params` 是即将与请求一起发送的 URL 参数
      //使用stringify转换前的格式是:{'accesstoken':'xxx'},转换后是 'accesstoken'='xxx'
    data: querystring.stringify(Object.assign({}, req.body, { // `data` 是作为请求主体被发送的数据 accesstoken: (needAccessToken && req.method === 'POST') ? user.accessToken : '' })), headers: {//避免 cnodejs 有的接口无法获取对应的数据格式 有的接口使用 from-data 'Content-Type': 'application/x-www-form-urlencoded' } }).then(resp => { if (resp.status === 200) { res.send(resp.data) } else { res.status(resp.status).send(resp.data) } }).catch(err => { if (err.response) { res.status(500).send(err.response.data) } else { res.status(500).send({ success: false, msg: '未知错误' }) } }) }

     执行 npm run dev:server 然后在chrome 浏览器中使用 postman插件进行 url 请求接口测试。

    页面上测试请求接口

    import React from 'react'
    import axios from 'axios'
    
    /* eslint-disable */ /*表示中间的代码不需要eslint去检测*/
    export default class TestApi extends React.Component {
    
      getTopics() {
        axios.get('/api/topics')
          .then(resp => {
            console.log(resp)
          }).catch(err => {
            console.log(err)
          })
      }
    
      login() {
        axios.post('/api/user/login', {
          accessToken: 'ef35af2e-95b4-4062-badc-419d3b'//登陆网站,我的页面获取
        }).then(resp => {
          console.log(resp)
        }).catch(err => {
          console.log(err)
        })
      }
    
      markAll() {
        axios.post('/api/message/mark_all?needAccessToken=true')
          .then(resp => {
            console.log(resp)
          }).catch(err => {
            console.log(err)
          })
      }
    
      render() {
        return (
          <div>
            <button onClick={this.getTopics}>topics</button>
            <button onClick={this.login}>login</button>
            <button onClick={this.markAll}>markAll</button>
          </div>
        )
      }
    }
    /* eslint-enable */
    config.devServer = {
      host: '0.0.0.0',
      compress: true,
      port: '8888',
      contentBase: path.join(__dirname, '../dist'),
      hot: true,
      overlay: {
        errors: true
      },
      publicPath: '/public/',
      historyApiFallback: {
        index: '/public/index.html'
      },
      proxy: { //在webpack.config.client.js 文件中配置本地服务器的路径
        '/api': 'http://localhost:3333'
      }
    }
    //这样在客户端访问的接口,可以代理到本地服务器上
  • 相关阅读:
    redis 五种数据结构详解(string,list,set,zset,hash)
    推荐一个同步Mysql数据到Elasticsearch的工具
    一些经验,用来鉴别不太靠谱的公司或工作(面试是双向的,是你最好的了解这个公司的机会)
    OpenSSL 使用 base64 编码/解码(liang19890820)
    Qt之QEvent(所有事件的翻译)
    Go 在 Windows 上用户图形界面 GUI 解决方案 Go-WinGUI 国产(使用cef 内核)
    卷积神经网络CNN
    Event Driven Architecture
    wineshark分析抓取本地回环包
    僵尸进程与孤儿进程
  • 原文地址:https://www.cnblogs.com/xiaozhumaopao/p/11026554.html
Copyright © 2011-2022 走看看