前后端分离项目

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

前后端分离项目

等待的猪   2021-01-22 我要评论

以前的项目:博客系统
这个项目是传统的开发方式,没有实现前后端分离。比较简单,没有跨域等问题。
在传统的开发方式中:界面中事先没有任何东西,用户输入网页地址之后,页面的内容和数据都是服务器返回的。
在前后端分离的开发方式中:页面是提前写好,数据通过Ajax请求而来的。

前后端分离项目

1.前端项目:myblog-pc,使用 vue-cli 搭建。
vue create myblog-pc
后端项目:myblog-rd,使用koa-generator创建(koa脚手架)
koa-generator
安装:npm install -g koa-generator
创建项目:koa2 myblog-rd
安装依赖:npm install

2.启动两个项目
myblog-pc:myblog-pc>npm run serve
myblog-rd:myblog-rd>npm start
myblog-rd项目启动之后,在网页中输入localhost:3000,会有服务器返回的值,表示服务器启动成功。

将前端项目和后端项目之间关联起来:前端点击按钮,后端传过来一个数据。
3.下载axiosnpm install --save axios vue-axios
axios
引入代码到vue项目的 main.js 文件中。

import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)

4.使用 axios

getData(){
      this.$http.get("http://localhost:3000").then((response) => {
          console.log(response.data)
      })
    }

默认访问到后端中的根路由

router.get('/', async (ctx, next) => {
  await ctx.render('index', {
    title: 'Hello Koa 2!'
  })
})

5.访问根路由的时候,希望服务器可以返回一个值,而不是渲染一个页面。

await ctx.render('index', {
    title: 'Hello Koa 2!'
  })

改为

router.get('/', async (ctx, next) => {
  ctx.body = "hello serve"
})

其中 ctx.body 就是服务端的返回值。
这时候在前端的 response 值就是服务器的返回值。
6.点击按钮之后会出现跨域问题

7.跨域问题的解决

  1. 访问控制允许设为 * 跨域
    操作: 将下面的代码复制在后端项目的 app.js 中
// 处理跨域
app.use(async (ctx, next) => {
  ctx.set("Access-Control-Allow-Origin", "*")
  // 继续执行下一个中间件
  await next()
})

这个方法不安全。

  1. CORS
    阮一峰cors
    npm koa-cors
    安装:npm install koa-cors
    在后端 app.js 中引入代码:
var cors = require('koa-cors');
app.use(cors());


8.两种请求
CORS是一个W3C标准,是跨域资源共享,克服了AJAX只能同源使用的限制。
使用的时候会有两个方式。

  1. 简单请求
getData(){
      this.$http.get("http://localhost:3000",{
        name:'lisi',
        age:23
      })
      .then((response) => {
          console.log(response)
      })
    }


Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain 。
但是大部分的前后端项目中,数据的传递都需要Content-Type字段的类型是application/json
2) 非简单请求
换成 post 请求

getData(){
      this.$http.post("http://localhost:3000",{
        name:'lisi',
        age:23
      })
      .then((response) => {
          console.log(response)
      })
    }


预检请求:测试服务器是否允许当前的域访问
正式请求:正式请求
两个请求会增加服务器的压力。

9.token
安装 jsonwebtoken token
生成和校验令牌的中间件。

10.在前端项目中,创建 / 和 /login 两个页面。
在 login 页面中,输入密码账号,点击按钮,执行 doLogin 方法

doLogin() {
      this.$http
        .post("http://localhost:3000/user/login", {
          username: this.username,
          password: this.password,
        })
        .then((res) => {
          if (res.data == "success") {
            this.$router.push('/');
          } else {
            alert('用户名或密码不正确!');
          }
        });
    },

访问"http://localhost:3000/user/login"路由,在服务器中 users.js 中

 doLogin() {
      this.$http
        .post("http://localhost:3000/users/login", {
          username: this.username,
          password: this.password,
        })
        .then((res) => {
          if (res.data == "success") {
            this.$router.push('/');
          } else {
            alert('用户名或密码不正确!');
          }
        });
    },

前端输入账号密码,传递给后端,后端验证。

router.prefix('/users')
router.post('/login', function (ctx, next) {
  let { username,password } = ctx.request.body
  if(username == "lisi" && password == "123456"){
    ctx.body = "success"
  }else{
    ctx.body = "fail"
  }
})

前端进入主页面之后,后端的数据传递给前端。

// 路由前缀
router.prefix('/blog')
router.get('/list', async (ctx, next) => {
  let blogs = [
    {
      blogId:11,
      title:"标题111",
      content:"内容111",
      postTime:new Date()
    },
    {
      blogId:22,
      title:"标题222",
      content:"内容222",
      postTime:new Date()
    },
    {
      blogId:33,
      title:"标题333",
      content:"内容333",
      postTime:new Date()
    }
  ]
  // 返回数据数组
  ctx.body = {
    blogs
  }

前端:

data(){
        return {
            blogList:[]
        }
    },
    created(){
        this.getData()
    },
    methods: {
        getData(){
            this.$http.get("http://localhost:3000/blog/list")
                .then((res) => {
                    let { blogs } = res.data;
                    // 将后端的数据传递给页面
                    this.blogList = blogs
                })
        }
    }

但是现在的问题是直接进入主页面,还是可以看到数据。
11. token的流程:

12.token的实现
登录成功之后,就生成token.
在 users,js 里面引入 jsonwebtoken

var jwt = require('jsonwebtoken');
let token = jwt.sign({ foo: 'bar' }, 'shhhhh');

jwt.sign()是token指令的生成算法。
{ foo: 'bar' }一般是账号,密码,或Id的验证信息。
'shhhhh'是随机写的,越复杂越好,将生成的 token 返回给客户端。

if(username == "lisi" && password == "123456"){
    // 登录成功
    // 生成 token
    let payload = {
      userId:Math.random(),
      username,
    }
    let token = jwt.sign(payload, '***my_scrret***');
    ctx.body = {
      status:"success",
      token
    }
  }

token 存放在 localstorage 中或者 vuex 中。

  • 在 vuex 中
export default new Vuex.Store({
  state: {
    token:""
  },
  // 同步
  mutations: {
  },
  // 异步
  actions: {
    setToken: (state,token) => {
      state.token = token;
      localStorage.setItem("mytoken",token)
    }
  },
  modules: {
    
  }
})

在页面中执行this.$store.dispatch('setToken', token)可以调用 vuex 中的方法。
再次发送请求的时候,就要携带 token。

 getData(){
             this.axios({
                url: "http://localhost:3000/blog/list",
                headers: {
                    "Authorization": localStorage.getItem('mytoken')
                }
            }).then((res) => {
                let {blogs} = res.data;
                this.blogList = blogs;
            });
        }

检验token

async (ctx, next) => {
  if(ctx.header.authorization){
    let token = ctx.header.authorization;
    try {
      // 验证token
      jwt.verify(token, '***my_scrret***');
      await next();
    } catch(err) {
      // err
      ctx.status = 401;
      ctx.body = "token不存在或已过期";
    }
  }
},

如果检验通过,就会执行下一个中间件,返回服务器中的数据。
在页面中渲染数据。
可以设置token的有效时间:let token = jwt.sign(payload, '***my_scrret***', {expiresIn: 10});

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们