> For the complete documentation index, see [llms.txt](https://zpliu.gitbook.io/booknote/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://zpliu.gitbook.io/booknote/vuex/deng-lu.md).

# 解构前端登录请求

## 封装request API

> 文中@一律代表 src目录

首先对请求地址进行封装，将请求与页面解构。在`@/api/user.js`中封装了与用户登录，信息查找等相关的前端请求

```javascript
import request from '@/utils/request'

export function login(data) {
  return request({
    url: '/login',
    method: 'post',
    data,  //发生给后端的数据，没有就填null
  })
}
```

## vuex进行状态管理

在vuex中封装一个与user操作有关的状态，

```javascript
const getDefaultState = () => {
  return {
    token: getToken(), //状态，用于判断当前是否已经登录
    username: '',
  }
}
const state = getDefaultState()

const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  SET_TOKEN: (state, token) => {
    state.token = token  //设置当前状态
  },
}
```

## 登录的异步操作

在html页面中启动异步操作，

* `loginForm`是登录组件的一个表单
* 使用`dispatch`启动异步的vuex任务，这里`action`的名字取决于`namespaced`
* 由于是登录操作，异步请求后不会得到数据，有数据也被放在vuex里了，因此`then`之后可以进行其他操作

```javascript
      this.$store
        .dispatch("user/login", {
          username: this.loginForm.username,
          password: cryptPW(this.loginForm.password),
        }) //加盐
        .then(() => {
          alert("登录成功");
        })
        .catch(() => {
          alert("登录失败");
        });
```

这里只注册了一个`login`的操作，当进行login操作的时候，返回一个`promise`对象，promise对象中调用`@/api/user.js`中的`login`请求；后台响应的数据首先在`@/utils/request.js`中会被拦截，如果请求没有出错的话将会返回一个response的Promise，否则返回一个Error的Promise

* 正常响应的数据在`then`方法中被捕获到，根据响应的数据提交`commit`设置vuex的状态，同时调用`setToken`设置cookie；最后将响应数据交给页面
* 异常的响应或者自定义的错误，由于Promise的链传递性最终将会被`catch`捕获

```javascript
const actions = {
  login({ commit }, userInfo) {
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
      login({ username: username.trim(), password: password })
        .then((reponse) => {
          const { token } = reponse.data
          commit('SET_TOKEN', token)
          setToken(token)
          resolve(reponse)
        })
        .catch((err) => {
          reject(err)
        })
    })
  },
}
```

## 响应拦截

* 正常响应代码为0
* 当响应出错时，返回一个`reject`，并且reject中是一个Error对象

```javascript
function handleReponse(response) {
  if (response.data && parseInt(response.data.code) === 0) {
    return response.data
  } else {
    switch (parseInt(response.data.code)) {
      case 0:
        break
      case 404:
        Notification.error({
          title: 'error',
          message: '后端接口网址未找到, 错误代码404',
          duration: 5000,
        })
        break
      default:
        Notification.error({
          title: 'error',
          message: '未知错误，错误代码:' + response.data.code,
          duration: 5000,
        })
    }
    return Promise.reject(
      new Error(
        response.data.code ? 'error code:' + response.data.code : 'Error'
      )
    )
  }
}
```
