webpack 配置react腳手架(六):api

1 訪問網址 https://cnodejs.org/api 能夠調取apihtml

2.//該body-parser 能夠將請求的body數據,轉變成 json 格式數據;
//express-session 用於在服務器端存放的session
//query-string 用於轉換 url 後面的請求參數 轉換成 json 格式node

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

 bodyParser中間件的研究react

3 使用方法:webpack

3.1 server.js 主程序:ios

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的登錄邏輯:web

//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.jschrome

//把用戶請求數據的接口,所有代理出去
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 請求接口測試。數據庫

頁面上測試請求接口express

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'
  }
}
//這樣在客戶端訪問的接口,能夠代理到本地服務器上
相關文章
相關標籤/搜索