axios node vue express

这篇博客记录了一位开发者在前后端交互过程中遇到的问题及解决方案,包括使用axios访问后台接口时的同源问题、参数传递、路由使用,以及在node.js中使用npm生成器进行后台开发。在前端,涉及Vue的子路由、watch与computed的区别,以及Ant Design Vue的使用。在后端,讨论了JWT的使用,包括token存储、鉴权和无感刷新token的实现。
摘要由CSDN通过智能技术生成

文章目录

day1

1. vue cliant design vue之前端建设

1. vue cli项目搭建
vue create demo
2. 使用ant deisign vue
  1. 官网

  2. 需要配置less时出现问题.bezierEasingMixin() 传送门

3. axios is not defined
cnpm i axios  
// main.js
import axios from 'axios'
Vue.prototype.$axios = axios
//使用
this.$axios
        .get('/login')
        .then(res => {
          console.log(res)
          this.verify = res.data
        })
        .catch(err => {
          console.error(err)
        })
4.localhost 8080接口访问3000后台,因为端口不同,同源协议生效,导致报错。
// vue.config.js 没有自行创建
module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000/',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
}
// main.js
axios.defaults.baseURL = '/api'
// 使用
this.$axios
        .get('/login')
        .then(res => {
          console.log(res)
          this.verify = res.data
        })
        .catch(err => {
          console.error(err)
        })
5.axios传参post后台接收不到,前端修改如下,后台通过req.query获取
this.$axios({
        method: 'post',
        url: '/login/doLogin',
        params: {
          username: this.form.name,
          psw: this.$md5(this.form.psw),
          captcha: this.form.captcha
        },
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
        }
      }).then(function (res) {
        console.log(res.data)
      })
6. 路由router使用

传送门

7.Cannot read property ‘$router‘ of undefined

传送门

2.npm 应用程序生成器之后台开发

1. 应用程序生成器
express --view=ejs expressGenerator
nodemon .\bin\www
2. app.js配置
var createError = require('http-errors')
var express = require('express')
const ejs = require('ejs')
const session = require('express-session')
const config = require('./config/config')
var path = require('path')
var logger = require('morgan')

const admin = require('./routes/admin/index')
const login = require('./routes/login')

var app = express()

// 配置模板引擎
app.engine('html', ejs.__express)
app.set('view engine', 'html')

app.use(logger('dev'))
app.use(express.urlencoded({ extended: false }))
app.use(express.static('static'))
// 配置中间件
app.use(
  session({
    secret: 'keyboard cat', // 服务器端生成session的签名
    name: 'captcha', // 修改session对应的cookie的名称
    resave: false, // 强制保存session即使它没有变化
    saveUninitialized: true, // 强制将未初始化的session存储
    cookie: {
      maxAge: 1000 * 60,
      secure: false // true表示只有https协议才能访问
    },
    rolling: true // 在每次请求时强行设置cookie,这将重置cookie过期时间(默认:false)
  })
)

// app.use('/' + config.adminPath, admin)
app.use('/', admin)
app.use('/login', login)

// 绑定全局模板变量
// app.locals.adminPath = config.adminPath
module.exports = app

3. svg-captcha使用
cnpm i svg-captcha --save
var svgCaptcha = require('svg-captcha')


router.get('/', function (req, res, next) {
  // 此处显示的是加减法运算哦
  var captcha = svgCaptcha.createMathExpr({
    width: 100,
    height: 40,
    background: 'white'
  })
  // 保存验证码
  req.session.captcha = captcha.text
  res.type('svg')
  res.status(200).send(captcha.data)
  console.log(captcha)
})
// 此处不知为何 vue前端src无法显示图片 使用v-html
<div v-html='verify'></div>

day2

1.vue ant-design前端

1. vue router子路由
const routes=[
    {path:"/demo1/:id",component:demo1,props:true},//props为true时,可以将动态路由的值传递给相应的组件
    {path:"/demo2",component:demo2},
    //{path:"/demo3",component:demo3,name:"test"},//name属性是给路由起别名,方便用js的方式去跳转
    {path:"/demo3/:id",component:demo3,name:"test"},//name属性是给路由起别名,方便用js的方式去跳转
    {path:"/demo4",component:demo4,children:[
        {path:"demo4-1",component:demo4a}
    ]},//name属性是给路由起别名,方便用js的方式去跳转
]
2. router 下的name属性用法

传送门

3. vue项目使用debugger

​ 在package.json\eslintConfig\rules

  "rules": {
      "no-debugger": "off",
      "no-console": "off"
    }

2. node 应用程序生成器

1. mongoose查询返回部分字段
  const result = await ManagerModel.find({}, ['_id', 'username', 'email', 'mobile', 'status'])

day3

1. vue ant-design前端

1. 封装post、get请求
2. axios 请求封装、拦截器
// request.js
import axios from 'axios'
import qs from 'qs'

const showStatus = status => {
  let message = ''
  switch (status) {
    case 400:
      message = '请求错误(400)'
      break
    case 401:
      message = '未授权,请重新登录(401)'
      break
    case 403:
      message = '拒绝访问(403)'
      break
    case 404:
      message = '请求出错(404)'
      break
    case 408:
      message = '请求超时(408)'
      break
    case 500:
      message = '服务器错误(500)'
      break
    case 501:
      message = '服务未实现(501)'
      break
    case 502:
      message = '网络错误(502)'
      break
    case 503:
      message = '服务不可用(503)'
      break
    case 504:
      message = '网络超时(504)'
      break
    case 505:
      message = 'HTTP版本不受支持(505)'
      break
    default:
      message = `连接出错(${status})!`
  }
  return `${message},请检查网络或联系管理员!`
}

const service = axios.create({
  // 联调
  baseURL: process.env.NODE_ENV === 'production' ? `/` : '/api',
  headers: {
    get: {
      'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
    },
    post: {
      'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
    }
  },
  // 是否跨站点访问控制请求
  withCredentials: true,
  timeout: 30000,
  // 此处get请求不需要,因为本就是username=admin&psw=21232f297a57a5a743894a0e4a801fc3&captcha=14形式
  transformRequest: [
    data => {
      data = qs.stringify(data)
      return data // username=admin&psw=21232f297a57a5a743894a0e4a801fc3&captcha=14
    }
  ],
  validateStatus() {
    // 使用async-await,处理reject情况较为繁琐,所以全部返回resolve,在业务代码中处理异常
    return true
  }
})

// 响应拦截器
service.interceptors.response.use(
  response => {
    const status = response.status
    let msg = ''
    if (status < 200 || status >= 300) {
      // 处理http错误,抛到业务代码
      msg = showStatus(status)
      if (typeof response.data === 'string') {
        response.data = { msg }
      } else {
        response.data.msg = msg
      }
    }
    return response
  },
  error => {
    // 错误抛到业务代码
    error.data = {}
    error.data.msg = '请求超时或服务器异常,请检查网络或联系管理员!'
    return Promise.resolve(error)
  }
)

export default service

// api.js
import service from './request'

//login page to show captcha
export const getCaptcha = params => service.get('/login', params)
export const postLoginInfo = params => service.post('/login/doLogin', params)

// managerList
export const getManageList = params => service.get('/', params)

2. qs.stringify()与JSON.stringify()序列化区别

qs.stringify()将对象 序列化成URL的形式,以&进行拼接。
JSON是正常类型的JSON

let ObjectDemo = {name:'weixin',age:12};
 qs.stringify(ObjectDemo)
// 'name=weixin&age=12'
JSON.stringify(ObjectDemo)
// '{"name":"weixin","age":12}'
3.transformRequesttransformResponse
 transformRequest:表示允许在向服务器发送前,修改请求数据
 1. 只能用在 ‘PUT’, ‘POST’ 和 ‘PATCH’ 这几个请求方法
 2. 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
 transformResponse:在传递给 then/catch 前,允许修改响应数据

day4

1. axios ant-design vue前端

1. vue父子组件传值
  1. 子传父

    // 子组件 search.vue 提交时emit
    
    handleSubmit() {
          // 传递name至父组件
          this.$emit('searchName', this.search.name)
        }
    
    // 父组件 manageList.vue
     <search v-on:searchName="getSearchName" />
       getSearchName(name) {
          console.log(name)
        }
    
  2. 父传子

    今天暂时没用到,链接粘在这里 可可爱爱

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qQpWuAPG-1639821415972)(C:\Users\26706\Desktop\20210415222059_1bd06.webp)]

    传送门

2. vuewatch

一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。

 watch: {
            num(newVal, oldVal) {
            // 监听 num 属性的数据变化
    		// 作用 : 只要 num 的值发生变化,这个方法就会被调用
    		// 第一个参数 : 新值
    		// 第二个参数 : 旧值,之前的值
                console.log('oldVal:',oldVal)
                console.log('newVal:',newVal)
            }
        }
 watch: {
            num: {
            	// 数据发生变化就会调用这个函数  
                handler(newVal, oldVal) {
                    console.log('oldVal:', oldVal)
                    console.log('newVal:', newVal)
                },
                // 立即处理 进入页面就触发
                immediate: true
            }
        }

对象和数组都是引用类型,引用类型变量存的是地址,地址没有变,所以不会触发watch。这时我们需要进行深度监听,就需要加上一个属性 deep,值为 true

 watch: {
            num: {
            	// 数据发生变化就会调用这个函数  
                handler(newVal, oldVal) {
                    console.log('oldVal:', oldVal)
                    console.log('newVal:', newVal)
                },
                // 立即处理 进入页面就触发
                immediate: true
                deep:true
            }
        }

3. watch和computed区别
watch 观察监听页面上的vue实例. eg.const vm=new vue({}),当需要在数据变化响应时,执行异步操作,或高性能操作,选择watch。

computed:关联多个实时计算的对象,当这个对象中的其中一个改变时都会触发这个属性;具有缓存能力。
4. ant deisgn vue使用model form时自定义验证
// addManager.vue 
rules: {
        mobile: [{ required: true, trigger: ['change', 'blur'], validator: tools.validatorMobile }],
        email: [{ required: true, trigger: ['change', 'blur'], validator: tools.validatorEmail }]
      },
       psw: [{ required: true, trigger: ['blur', 'change'], validator: tools.validatorPsw }],

// too.js
// 验证手机号 FormModel
  validatorMobile(rule, value, callback) {
    // 如果为空值,就抛出错误
    if (!value) {
      callback(new Error('请输入手机号!'))
    } else {
      // 正则判断手机号格式的格式,正则判断失败抛出错误,否则直接callback()
      if (!/^1[2-9]\d{9}$/.test(value)) {
        callback(new Error('手机号格式不正确!'))
      } else {
        callback()
      }
    }
  },
  //   验证邮箱 FormModel
  validatorEmail(rule, value, callback) {
    // 正则判断手机号格式的格式,正则判断失败抛出错误,否则直接callback()
    if (value) {
      if (!/^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/.test(value)) {
        callback(new Error('邮箱格式不正确!'))
      } else {
        callback()
      }
    }
  },
 // 密码至少包含 数字和英文,长度6-20
  validatorPsw(rule, value, callback) {
    if (value) {
      if (!/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/.test(value)) {
        callback(new Error('密码至少包含 数字和英文,长度6-20!'))
      } else {
        callback()
      }
    } else {
      callback(new Error('请输入密码!'))
    }
  },

切记:如果对表单信息设置validator,其必须为required,否则submit失败

简单密码正则表达式

5. 为每条post请求增加add_time
// request.js
transformRequest: [
    data => {
        // 判断data原因是 get请求的data为undefined,无法增加add_time
      if (data) {
        data['add_time'] = tools.getUnix()
      }
      data = qs.stringify(data)
      console.log(data)
      return data
    }
  ],
    
6. 路由守卫已登录未退出不能去login
router.beforeEach((to, from, next) => {
  // 获取token
  const tokenStr = window.localStorage.getItem('token')
  if ((to.path === '/login' || to.path === '/') && tokenStr) {
    Vue.prototype.$message.warn('您已经登录')
    next('/main')
  } else {
    next()
  }
  if (!tokenStr) {
    return next('/login')
  } else {
    if (to.path !== '/login') {
      next()
    }
  }
})
7. ant deisgn vue 对话框使用
// main.js
import { Modal} from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
Vue.prototype.$confirm = Modal.confirm

 // main.vue
 const that = this
      this.$confirm({
        title: '您确定要退出该账户吗?',
        content: '当退出后,您需要重新登录',
        okText: '确定',
        cancelText: '取消',
        onOk() {
          localStorage.removeItem('token')
          that.$router.replace('/login')
        },
        onCancel() {}
      })

2. node js应用程序生成器

1. get请求带参数,前端传参
// 前端 api.js 参数为{params}以使得在后台以req.query形式获取 此时不经过transformRequest
export const getManagerList = params => service.get('/', { params })
// 后端 index.js
router.get('/', async function (req, res, next) {
  let result
  if (req.query.username) {
    result = await ManagerModel.find({ username: req.query.username }, ['_id', 'username', 'email', 'mobile', 'status'])
  } else {
    result = await ManagerModel.find({}, ['_id', 'username', 'email', 'mobile', 'status'])
  }
  res.send(result)
})
2. session负载均衡,保存至数据库
const MongoStore = require('connect-mongo')
app.use(
  session({
    secret: 'keyboard cat', // 服务器端生成session的签名
    resave: false, // 强制保存session即使它没有变化
    saveUninitialized: true, // 强制将未初始化的session存储
    cookie: {
      maxAge: 1000 * 60 * 60,
      secure: false // true表示只有https协议才能访问
    },
    rolling: true, // 在每次请求时强行设置cookie,这将重置cookie过期时间(默认:false)
    store: MongoStore.create({
      mongoUrl: config.dbUrl
    })
  })
)
3. 使用session,进而后台根据session判断 处理未登录返回401 拦截器拦截
app.use('/', (req, res, next) => {
  var pathname = url.parse(req.url).pathname
  if (req.session.userinfo) {
  	// 还需与后台数据库比对
    next()
  } else {
    if (pathname === '/login' || pathname === '/doLogin') {
      next()
    } else {
      res.send(401)
    }
  }
})
  1. 在拦截器里进行res拦截。

    service.interceptors.response.use(
      response => {
        const status = response.status
        let msg = ''
        // 坏了,你没登录
        if (status === 401) {
            // 此处页面会闪动,并非实现真正拦截
          router.replace({ path: '/login' })
          return
        }
        if (status < 200 || status >= 300) {
          // 处理http错误,抛到业务代码
          msg = showStatus(status)
          if (typeof response.data === 'string') {
            response.data = { msg }
          } else {
            response.data.msg = msg
          }
        }
        return response
      },
      error => {
        // 错误抛到业务代码
        error.data = {}
        error.data.msg = '请求超时或服务器异常,请检查网络或联系管理员!'
        return Promise.resolve(error)
      }
    )
    

    登录后才能进入首页,以上结果其效果不太好,因为实际还是去了操作者想去的页面,也去后台获取了数据。只不过被强制转到login页面了。

4. token JWT 路由守卫 中间件 localStorage 鉴权
// jwt.js
const jwt = require('jsonwebtoken')
// 秘钥
const jwtSecret = '110futurenodemongodbvue'
// 加密 参数是要存入到token中的信息
exports.generateToken = (userName, userId) => {
  const token = jwt.sign({ userName, userId }, jwtSecret, { expiresIn: '24h' })
  return token
}
exports.getToken = token => {
  return new Promise((resolve, reject) => {
    if (!token) {
      reject({ error: 'token是空的' })
    } else {
      const info = jwt.verify(JSON.parse(token), jwtSecret)
      resolve(info) //解析返回的值
    }
  })
}

  1. 登录成功后,设置返回token
// login.js
router.post('/doLogin', async (req, res) => {
  let username = req.body.username
  let psw = req.body.psw
  let captcha = req.body.captcha
  if (Number(captcha) !== Number(req.session.captcha)) {
    res.send({ err: 1, msg: '验证码错误' })
    return
  }
  let result = await ManagerModel.find({ username: username })
  if (result.length > 0) {
    if (psw !== result[0].password) {
      res.send({ err: 1, msg: '密码错误' })
      return
    }
    const token = jwt.generateToken(username, result[0]._id)

    res.send({ token, err: 0, msg: '登录成功' })
  } else {
    res.send({ err: 1, msg: '用户不存在' })
    return
  }
})
  1. 在前端获取token,保存至本地
 postLoginInfo({ username: this.form.name, psw: this.$md5(this.form.psw), captcha: this.form.captcha }).then(function (res) {
            console.log(res)
            if (res.data.err !== 0) {
              // 刷新验证码
              that.$message.error(res.data.msg)
              return
            }
            localStorage.setItem('token', JSON.stringify(res.data.token))
            that.$message.success(res.data.msg)
            // 组件传name至main
            that.$router.push({ path: '/main' })
          })
        
  1. 在登录成功后,进入页面请求数据需要在headers里携带token返回,让服务器解密判断登录状态

    // request.js 拦截器
    service.interceptors.request.use(
      config => {
        if (localStorage.token) {
          config.headers.Authorization = localStorage.token //将token设置成请求头
        }
        return config
      },
      error => {
        // 错误抛到业务代码
        error.data = {}
        error.data.msg = '服务器异常,请联系管理员!'
        return Promise.resolve(error)
      }
    )
    
  2. 后台在调用接口时都会去看token是否存在,并解密是否成功,只有成功后才会返回需要的数据

    app.use((req, res, next) => {
      // 不需要进行验证的api,白名单
      var urlArr = ['/login', '/login/doLogin', '/register']
      if (urlArr.indexOf(req.url) >= 0) {
        next()
        return false
      }
      const token = req.headers['authorization']
      getToken(token)
        .then(data => {
          console.log(data)
          if (!data) {
            res.send({ err: 401, msg: 'token信息错误,不存在,过期' })
          } else {
            // 验证成功  放行
            next()
          }
        })
        .catch(error => {
          //  解析是空的
          res.send({ err: 401, msg: 'token信息错误,不存在,过期' })
        })
    })
    
  3. 在使用session时,在前端的拦截器里进行err判断,进而使用router.replace进行路由跳转至login,但其实该方法用户体验不好。

    所以决定使用路由守卫+message提示来跳转至login.

    
    /* 配置路由 */
    const routes = [
      { path: '/login', component: login, alias: '/' }, // /的别名是login
      {
        path: '/main',
        meta: {
          requireAuth: true // 该路由项需要权限校验
        },
        redirect: '/manager/managerList',
        component: main,
        children: [
          { path: '/manager/managerList', component: ManagerList },
          { path: '/manager/addManager', component: AddManager },
          { path: '/nav/navList', component: NavList },
          { path: '/nav/addNav', component: AddNav },
          { path: '/slide/slideList', component: SlideList },
          { path: '/slide/addSlide', component: AddSlide },
          { path: '/content/contentList', component: ContentList },
          { path: '/content/addContent', component: AddContent }
        ]
      }
    ]
    
    router.beforeEach((to, from, next) => {
      // if (to.path === '/login') return next()
      // 或者可以使用
      if (!to.meta.requireAuth) {
        return next()
      }
      // 获取token
      const tokenStr = window.localStorage.getItem('token')
      if (!tokenStr) return next('/login')
      next()
    })
    
5 JWT Token Session
  1. JSON Web Token,用户会话信息存储在客户端浏览器中,各方之间通过JSON对象安全传输信息,这些信息可以通过加密算法进行加密。

​ 2. Token指访问资源的凭据,是一种身份认证的方式,它是解决跨域认证的最流行的一种方式。

​ 通过session去做身份认证,session是通过服务器中保存会话数据来做身份认证,这种方式会导致在高并发中服务器压力过大的情况,还有就是,如果是服务器集群,那么就需要这些服务器session共享。

  1. 传统token与JST区别

    • 传统Token

      用户发起登录请求,登录成功之后返回Token,并且存于数据库,用户访问资源的时候需要携带Token,服务端获取Token之后和数据库中的对比。

    • JWT

      用户发起登录请求,登录成功之后返回Token,但是不存于数据库,用户访问资源的时候需要携带Token,服务端获取Token之后去校验Token的合法性。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PBBsQwIF-1639821415974)(C:\Users\26706\AppData\Roaming\Typora\typora-user-images\image-20211218163106332.png)]

    HMACSHA256(
        base64UrlEncode(header) + "." +
        base64UrlEncode(payload),
        secret
    )
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-svtuaW2n-1639821415974)(C:\Users\26706\AppData\Roaming\Typora\typora-user-images\image-20211218163126566.png)]

6. JWT中token存储在哪里

传送门

7. token相较于session而言的优点

传送门

8. 实现无感刷新token

传送门

​ 评论说:返回一个access_token和refresh_token,每次请求带上这两个token,后端拦截器判断,先判断鉴权token是否有效和过期,如果有效的话,就允许访问。如果过期了,就判断刷新token是否有效,如果有效,就返回指定状态码,然后让前端根据这个状态码去吊用刷新token接口。如果刷新token失效了,就提示需要重新登录!

无需鉴权 有token 去不了login

需鉴权 有token 首页

功之后返回Token,并且存于数据库,用户访问资源的时候需要携带Token,服务端获取Token之后和数据库中的对比。

- JWT

  用户发起登录请求,登录成功之后返回Token,但是不存于数据库,用户访问资源的时候需要携带Token,服务端获取Token之后去校验Token的合法性。

[外链图片转存中...(img-PBBsQwIF-1639821415974)]

```javascript
HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    secret
)
```

[外链图片转存中...(img-svtuaW2n-1639821415974)]
6. JWT中token存储在哪里

传送门

7. token相较于session而言的优点

传送门

8. 实现无感刷新token

传送门

​ 评论说:返回一个access_token和refresh_token,每次请求带上这两个token,后端拦截器判断,先判断鉴权token是否有效和过期,如果有效的话,就允许访问。如果过期了,就判断刷新token是否有效,如果有效,就返回指定状态码,然后让前端根据这个状态码去吊用刷新token接口。如果刷新token失效了,就提示需要重新登录!

无需鉴权 有token 去不了login

需鉴权 有token 首页

需鉴权 无token login

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Vue Express MySQL项目源码是一个使用Vue.jsExpress和MySQL构建的全栈应用程序的代码库。该应用程序提供了一个用户管理系统,允许用户注册、登录和管理他们的个人资料。 项目的文件结构通常分为前端和后端两部分。前端使用Vue.js来构建用户界面,包括注册和登录表单、个人资料页面以及其他相关页面。前端文件夹中包含各种Vue组件,用于显示数据、处理用户输入以及与后端API进行通信。 后端使用Express框架来处理路由和请求,与MySQL数据库进行交互。后端文件夹中包含各种路由文件,用于处理用户注册、登录和个人资料的请求。此外,还有一个名为"db.js"的文件,用于建立与MySQL数据库的连接,并执行相关的数据库操作。 在前端和后端之间进行通信时,通常使用axios库来发送异步请求。前端组件会将用户提交的注册和登录数据发送到后端,后端将验证这些数据,并根据情况返回成功或失败的响应。用户登录成功后,后端将生成一个JSON Web Token(JWT),以便在后续的请求中进行身份验证。 此外,该项目还可以包括密码加密、表单验证、拦截器、错误处理等功能,以提高安全性和用户体验。 总之,Vue Express MySQL项目源码提供了一个完整的全栈应用程序的实现,具有用户注册、登录和管理功能,通过使用Vue.jsExpress和MySQL等技术,能够实现前后端的数据交互和业务逻辑处理。 ### 回答2: Vue+Express+MySQL是一种常见的全栈开发技术栈,用于构建基于Web的应用程序。该技术栈的项目源码包括了前端vue框架、后端express框架以及数据库MySQL的代码。 Vue是一种流行的JavaScript框架,用于构建交互式的前端界面。Vue具有简单易学的API和灵活的组件化架构,使得开发者可以更快速地构建响应式的用户界面。 Express是一个基于Node.js的后端框架,用于构建和管理服务器端应用。Express具有轻量级、灵活和可扩展的特点,支持开发REST API和处理HTTP请求。 MySQL是一种关系型数据库管理系统,用于存储和管理数据。它具有开源、高性能和可靠的特点,广泛应用于各种规模的应用程序。 在Vue+Express+MySQL项目源码中,前端代码主要是使用Vue框架编写的组件和页面,用于实现用户界面和与后端交互。例如,可以编写Vue组件来呈现数据、处理用户输入和发起HTTP请求。 后端代码主要是使用Express框架编写的路由和逻辑处理部分,用于处理前端发起的HTTP请求并返回数据。例如,可以编写Express路由来处理用户登录请求、查询数据库并返回结果。 数据库部分主要是使用MySQL数据库来存储和管理数据。例如,可以创建表格来存储用户信息、商品信息等,并通过使用MySQL查询语言来实现数据的增删改查等操作。 综上所述,Vue+Express+MySQL项目源码包括了前端Vue代码、后端Express代码和数据库MySQL的代码,通过这些代码可以实现一个完整的全栈应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值