以一个典型 Vue 前端项目 为例,详细说明前端如何和后端进行接口联调。内容会覆盖:环境配置、接口封装、代理跨域、请求调试、登录鉴权、联调流程、常见问题等。


一、前后端联调前需要先确认什么?

在开始联调接口之前,前端和后端需要先对齐以下内容。

1. 接口文档

通常后端会提供接口文档,例如:

  • Swagger / Knife4j
  • Apifox
  • Postman 文档
  • YApi
  • Markdown / Wiki 文档

前端需要重点确认:

接口地址:/api/user/list
请求方式:GET / POST / PUT / DELETE
请求参数:query / params / body
请求头:Content-Type、Authorization
响应结构:code、data、message
错误码:401、403、500 等

例如:

{
  "code": 200,
  "message": "success",
  "data": {
    "list": [],
    "total": 0
  }
}

2. 后端服务地址

需要知道后端本地或测试环境地址,例如:

http://localhost:8080
http://192.168.1.100:8080
https://test-api.xxx.com

前端开发环境一般不会直接写死完整地址,而是通过代理或环境变量配置。

3. 是否需要登录鉴权

确认接口是否需要:

  • token
  • cookie
  • session
  • Authorization 请求头
  • refresh token
  • csrf token

例如:

Authorization: Bearer xxxxxx

二、Vue 项目中如何配置后端接口地址?

Vue 项目常见有两类:

  • Vue CLI 创建的项目
  • Vite 创建的 Vue 项目

现在新项目大多使用 Vite,下面两种都说一下。


三、Vite + Vue 项目接口联调配置

1. 配置环境变量

在项目根目录下创建:

.env.development
.env.production
.env.test

例如 .env.development

VITE_API_BASE_URL=/api

.env.production

VITE_API_BASE_URL=https://api.xxx.com

在代码中使用:

const baseURL = import.meta.env.VITE_API_BASE_URL

注意:Vite 环境变量必须以 VITE_ 开头。


2. 配置开发代理

在 vite.config.js 或 vite.config.ts 中配置:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  server: {
    host: '0.0.0.0',
    port: 5173,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, '')
      }
    }
  }
})

含义:

前端请求:/api/user/list
实际转发:http://localhost:8080/user/list

如果后端接口本身就带 /api 前缀,比如:

http://localhost:8080/api/user/list

那就不要 rewrite:

proxy: {
  '/api': {
    target: 'http://localhost:8080',
    changeOrigin: true
  }
}

四、Vue CLI 项目接口联调配置

如果是 Vue CLI 项目,在 vue.config.js 中配置:

module.exports = {
  devServer: {
    port: 8081,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
}

前端请求:

axios.get('/api/user/list')

实际转发到:

http://localhost:8080/user/list

五、封装 axios 请求

实际项目中不建议每个页面直接写 axios.get(),通常会统一封装。

1. 安装 axios

npm install axios

或者:

yarn add axios

2. 创建 request 实例

例如目录结构:

src
 ├─ api
 │   ├─ user.js
 │   └─ login.js
 ├─ utils
 │   └─ request.js
 ├─ views
 └─ main.js

创建 src/utils/request.js

import axios from 'axios'
import router from '@/router'

const service = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 10000
})

// 请求拦截器
service.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token')

    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }

    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
service.interceptors.response.use(
  response => {
    const res = response.data

    if (res.code !== 200) {
      console.error(res.message || '接口请求失败')
      return Promise.reject(res)
    }

    return res.data
  },
  error => {
    if (error.response) {
      const status = error.response.status

      if (status === 401) {
        localStorage.removeItem('token')
        router.push('/login')
      }
    }

    return Promise.reject(error)
  }
)

export default service

这样页面中就不用重复处理 token、错误码等逻辑。


六、按模块管理接口

例如 src/api/user.js

import request from '@/utils/request'

export function getUserList(params) {
  return request({
    url: '/user/list',
    method: 'get',
    params
  })
}

export function getUserDetail(id) {
  return request({
    url: `/user/${id}`,
    method: 'get'
  })
}

export function createUser(data) {
  return request({
    url: '/user/create',
    method: 'post',
    data
  })
}

export function updateUser(data) {
  return request({
    url: '/user/update',
    method: 'put',
    data
  })
}

export function deleteUser(id) {
  return request({
    url: `/user/${id}`,
    method: 'delete'
  })
}

页面中使用:

<script setup>
import { ref, onMounted } from 'vue'
import { getUserList } from '@/api/user'

const list = ref([])
const loading = ref(false)

const fetchUserList = async () => {
  loading.value = true
  try {
    const data = await getUserList({
      pageNum: 1,
      pageSize: 10
    })
    list.value = data.list
  } catch (error) {
    console.error('获取用户列表失败', error)
  } finally {
    loading.value = false
  }
}

onMounted(() => {
  fetchUserList()
})
</script>

七、GET、POST 参数如何传?

1. GET 请求传 query 参数

接口:

GET /user/list?pageNum=1&pageSize=10

前端:

request({
  url: '/user/list',
  method: 'get',
  params: {
    pageNum: 1,
    pageSize: 10
  }
})

axios 中:

  • params 会拼接到 URL 后面
  • 适用于 GET、DELETE 等请求

2. POST 请求传 JSON body

接口:

POST /user/create
Content-Type: application/json

前端:

request({
  url: '/user/create',
  method: 'post',
  data: {
    username: '张三',
    age: 18
  }
})

axios 中:

  • data 是请求体
  • 常用于 POST、PUT、PATCH

3. 表单格式 application/x-www-form-urlencoded

如果后端要求表单格式:

import qs from 'qs'

request({
  url: '/login',
  method: 'post',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  data: qs.stringify({
    username: 'admin',
    password: '123456'
  })
})

安装:

npm install qs

4. 上传文件 multipart/form-data

const formData = new FormData()
formData.append('file', file)

request({
  url: '/upload',
  method: 'post',
  data: formData,
  headers: {
    'Content-Type': 'multipart/form-data'
  }
})

八、登录接口如何联调?

常见登录流程:

  1. 用户输入账号密码
  2. 调用登录接口
  3. 后端返回 token
  4. 前端保存 token
  5. 后续请求自动带上 token
  6. token 失效跳转登录页

接口:

POST /login

响应:

{
  "code": 200,
  "message": "success",
  "data": {
    "token": "xxxxxx"
  }
}

前端代码:

import request from '@/utils/request'

export function login(data) {
  return request({
    url: '/login',
    method: 'post',
    data
  })
}

页面:

const handleLogin = async () => {
  try {
    const data = await login({
      username: form.username,
      password: form.password
    })

    localStorage.setItem('token', data.token)
    router.push('/home')
  } catch (error) {
    console.error('登录失败', error)
  }
}

请求拦截器自动添加:

config.headers.Authorization = `Bearer ${token}`

如果后端要求的是:

token: xxxxxx

那就写:

config.headers.token = token

这个要和后端约定清楚。


九、如何解决跨域问题?

前端本地一般是:

http://localhost:5173

后端可能是:

http://localhost:8080

协议、域名、端口任一不同,就会产生跨域。

方案一:前端开发代理

开发环境推荐使用代理:

server: {
  proxy: {
    '/api': {
      target: 'http://localhost:8080',
      changeOrigin: true,
      rewrite: path => path.replace(/^\/api/, '')
    }
  }
}

这是开发环境最常用方式。

方案二:后端开启 CORS

后端响应头设置:

Access-Control-Allow-Origin: http://localhost:5173
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
Access-Control-Allow-Headers: Content-Type,Authorization

如果涉及 cookie,还需要:

Access-Control-Allow-Credentials: true

前端 axios:

axios.defaults.withCredentials = true

注意:使用 credentials 时,后端不能设置:

Access-Control-Allow-Origin: *

十、如何判断接口有没有真正调通?

可以从浏览器开发者工具看。

1. 打开 Network 面板

Chrome 浏览器:

F12 -> Network -> Fetch/XHR

查看:

  • Request URL
  • Request Method
  • Status Code
  • Request Headers
  • Request Payload
  • Response

2. 重点检查 Request URL

例如前端发起:

http://localhost:5173/api/user/list

通过代理后,实际后端收到:

http://localhost:8080/user/list

如果浏览器 Network 里看到 404,要确认:

  • 前端接口路径是否写错
  • 代理 rewrite 是否写错
  • 后端接口是否有前缀
  • 请求方式 GET/POST 是否正确

3. 查看请求参数

GET 参数看:

Query String Parameters

POST JSON 参数看:

Request Payload

表单参数看:

Form Data

4. 查看响应数据

Response 中确认:

{
  "code": 200,
  "data": {},
  "message": "success"
}

如果接口返回成功,但页面不显示,通常是前端取值路径不对。

例如返回:

{
  "code": 200,
  "data": {
    "records": [],
    "total": 0
  }
}

但前端写的是:

list.value = data.list

这就会显示为空,应该改为:

list.value = data.records

十一、联调接口的推荐流程

一个比较规范的联调流程如下:

第一步:后端先用接口工具自测

后端先在 Swagger、Postman、Apifox 中测试接口是否正常。

确认:

  • 接口能访问
  • 参数正确
  • 响应结构稳定
  • 错误码符合约定

第二步:前端用接口工具测试

前端也可以先用 Apifox/Postman 调接口。

目的:

  • 排除前端代码问题
  • 确认接口文档是否准确
  • 确认 token、参数、响应字段

第三步:前端配置代理

例如:

proxy: {
  '/api': {
    target: 'http://后端地址:端口',
    changeOrigin: true,
    rewrite: path => path.replace(/^\/api/, '')
  }
}

配置完需要重启前端服务:

npm run dev

注意:修改 vite.config.js 后必须重启。


第四步:封装 API 方法

export function getUserList(params) {
  return request({
    url: '/user/list',
    method: 'get',
    params
  })
}

第五步:页面调用接口

const data = await getUserList({ pageNum: 1, pageSize: 10 })

第六步:根据 Network 排查问题

重点看:

  • URL 对不对
  • method 对不对
  • headers 对不对
  • 参数对不对
  • response 对不对
  • status code 是多少

十二、常见联调问题和解决办法

1. 404 Not Found

可能原因:

  • 接口地址写错
  • 前端多写或少写 /api
  • 代理 rewrite 配置错误
  • 后端接口路径和文档不一致
  • 请求方式错误,比如接口是 POST,前端用了 GET

解决:

// 如果后端接口是 http://localhost:8080/api/user/list
// 前端请求 /api/user/list
// proxy 不要 rewrite
proxy: {
  '/api': {
    target: 'http://localhost:8080',
    changeOrigin: true
  }
}

2. 401 Unauthorized

可能原因:

  • 没传 token
  • token 过期
  • token 格式不对
  • 请求头字段名不对

检查:

Authorization: Bearer token

还是:

token: token

需要和后端约定。


3. 403 Forbidden

可能原因:

  • 用户没有权限
  • 后端权限配置限制
  • csrf 校验失败
  • token 有效但权限不足

4. 500 Internal Server Error

通常是后端代码异常。

前端需要提供给后端:

  • 请求 URL
  • 请求方法
  • 请求参数
  • 请求头
  • 报错时间
  • 后端返回内容

5. CORS 跨域错误

如果控制台出现:

Access to XMLHttpRequest has been blocked by CORS policy

解决:

  • 开发环境用前端代理
  • 或后端配置 CORS

注意代理只在开发环境生效,生产环境要用 nginx 或后端 CORS。


6. 请求没有走代理

常见原因:

baseURL: 'http://localhost:8080'

如果你写了完整后端地址,请求就不会走 Vite 代理。

开发环境想走代理,一般写:

baseURL: '/api'

然后由代理转发。


7. 修改代理后不生效

原因:

  • 没重启项目
  • vite.config.js 写错位置
  • 请求路径没有以 /api 开头

解决:

npm run dev

重新启动。


十三、生产环境如何处理接口地址?

开发环境可以用 Vite 代理,但生产环境打包后代理不生效。

生产环境常见方案:

方案一:前端直接请求完整 API 域名

.env.production

VITE_API_BASE_URL=https://api.xxx.com

打包后请求:

https://api.xxx.com/user/list

需要后端配置 CORS。


方案二:Nginx 反向代理

前端部署在:

https://www.xxx.com

接口请求:

https://www.xxx.com/api/user/list

Nginx 配置:

server {
  listen 80;
  server_name www.xxx.com;

  location / {
    root /usr/share/nginx/html;
    index index.html;
    try_files $uri $uri/ /index.html;
  }

  location /api/ {
    proxy_pass http://backend:8080/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

这样生产环境也不会跨域。


十四、联调时前后端怎么高效沟通?

推荐每个问题都按照下面格式反馈:

接口:GET /user/list
环境:http://test-api.xxx.com
问题:返回 500
请求参数:pageNum=1&pageSize=10
请求头:Authorization 已传
返回结果:xxx
复现时间:2025-xx-xx 10:30
截图:Network 截图

不要只说:

接口报错了

这样后端很难排查。


十五、一个完整的 Vue 联调示例

1. .env.development

VITE_API_BASE_URL=/api

2. vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, '')
      }
    }
  }
})

3. src/utils/request.js

import axios from 'axios'

const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 10000
})

request.interceptors.request.use(config => {
  const token = localStorage.getItem('token')
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

request.interceptors.response.use(
  response => {
    const res = response.data
    if (res.code !== 200) {
      return Promise.reject(res)
    }
    return res.data
  },
  error => Promise.reject(error)
)

export default request

4. src/api/user.js

import request from '@/utils/request'

export function getUserList(params) {
  return request({
    url: '/user/list',
    method: 'get',
    params
  })
}

5. 页面调用

<script setup>
import { ref, onMounted } from 'vue'
import { getUserList } from '@/api/user'

const userList = ref([])

onMounted(async () => {
  const data = await getUserList({
    pageNum: 1,
    pageSize: 10
  })

  userList.value = data.list
})
</script>

请求链路是:

页面调用 getUserList
        ↓
axios 请求 /api/user/list
        ↓
Vite dev server 代理
        ↓
http://localhost:8080/user/list
        ↓
后端返回数据
        ↓
响应拦截器处理
        ↓
页面渲染

十六、总结

Vue 前端和后端联调接口,核心就是这几件事:

  1. 先确认接口文档:地址、方法、参数、响应结构。
  2. 配置环境变量:开发、测试、生产环境分开。
  3. 配置代理解决跨域:Vite 用 server.proxy,Vue CLI 用 devServer.proxy
  4. 统一封装 axios:处理 baseURL、token、错误码、超时。
  5. 按模块管理 API:页面只调用业务方法,不直接写请求细节。
  6. 用 Network 排查问题:看 URL、method、headers、payload、response。
  7. 生产环境用 Nginx 或 CORS:开发代理打包后不会生效。
  8. 和后端按请求信息沟通:提供接口、参数、响应、截图,方便定位。

如果是实际项目,推荐形成固定结构:

src/api        // 接口方法
src/utils/request.js // axios 封装
.env.*         // 环境变量
vite.config.js // 开发代理

这样后续无论是登录、列表、详情、增删改查,联调都会比较清晰、稳定。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐