——跨域、热更新、容器化部署一网打尽
在微服务与敏捷开发盛行的今天,前后端分离架构已成为企业级应用的标配。本文将通过12个实战代码示例、跨域问题终极解决方案和Docker部署全流程,手把手教你实现:
工具 | 版本要求 | 官网链接 |
---|---|---|
.NET 8 SDK | 8.0.100+ | .NET下载页面 |
Node.js | 18.16.0+ | Node.js官网 |
Vue CLI | 4.5.17+ | npm install -g @vue/cli |
Visual Studio | 2022+ | VS下载 |
# 创建基于Minimal API的Web API项目
dotnet new webapi -n MyApiServer -o MyApiServer
cd MyApiServer
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// 1. 配置CORS(允许所有来源测试用)
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowAll", policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
// 2. 配置Swagger(开发环境调试必装)
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// 3. 使用MapGroup实现路由分组
app.UseCors("AllowAll");
app.UseSwagger();
app.UseSwaggerUI();
app.MapGroup("/api/v1")
.AddApiVersioning()
.MapControllers(); // 自动扫描Controllers目录
app.Run();
vue create my-vue-app --default
cd my-vue-app
// vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:5173', // 后端开发环境地址
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
}
}
};
// src/api/index.js
import axios from 'axios';
const apiClient = axios.create({
baseURL: process.env.NODE_ENV === 'production'
? '/api' // 生产环境部署时需配置反向代理
: 'http://localhost:5000/api/v1', // 开发环境直接对接后端
headers: { 'Content-Type': 'application/json' }
});
// 统一错误处理
apiClient.interceptors.response.use(
response => response,
error => {
if (error.response.status === 401) {
// 跳转登录页
window.location.href = '/login';
}
return Promise.reject(error);
}
);
export default apiClient;
// Controllers/UsersController.cs
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/v1/[controller]")]
public class UsersController : ControllerBase
{
private readonly IUserService _userService;
public UsersController(IUserService userService)
{
_userService = userService;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetById(int id)
{
var user = await _userService.GetUserByIdAsync(id);
return user == null
? NotFound(new { message = "用户不存在" })
: Ok(user);
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] CreateUserDto dto)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
var userId = await _userService.CreateUserAsync(dto);
return CreatedAtAction(
nameof(GetById),
new { id = userId },
new { id = userId }
);
}
[HttpPut("{id}")]
public async Task<IActionResult> Update(int id, [FromBody] UpdateUserDto dto)
{
await _userService.UpdateUserAsync(id, dto);
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
await _userService.DeleteUserAsync(id);
return NoContent();
}
}
CreatedAtAction
:自动生成资源URL,遵循RESTful规范。NoContent()
:PUT/DELETE请求成功时返回204状态码。ModelState
:内置验证机制,配合DTO实现数据解耦。
用户ID: {{ user.id }}
姓名: {{ user.name }}
邮箱: {{ user.email }}
加载中...
// Services/IdentityService.cs
public class IdentityService : IIdentityService
{
private readonly SymmetricSecurityKey _key;
public IdentityService(IConfiguration config)
{
_key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(config["Jwt:Key"]));
}
public string GenerateToken(User user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.UserName)
};
var creds = new SigningCredentials(
_key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "MyApiServer",
audience: "MyVueApp",
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
// src/store/auth.js (Vuex)
import apiClient from '@/api';
const state = {
token: localStorage.getItem('token') || null
};
const mutations = {
SET_TOKEN(state, token) {
state.token = token;
localStorage.setItem('token', token);
apiClient.defaults.headers.common['Authorization'] = `Bearer ${token}`;
},
CLEAR_TOKEN(state) {
state.token = null;
localStorage.removeItem('token');
delete apiClient.defaults.headers.common['Authorization'];
}
};
const actions = {
async login({ commit }, { username, password }) {
const response = await apiClient.post('/auth/login', { username, password });
commit('SET_TOKEN', response.data.token);
},
logout({ commit }) {
commit('CLEAR_TOKEN');
}
};
# MyApiServer/Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyApiServer.csproj", "./"]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApiServer.dll"]
# my-vue-app/Dockerfile
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
// 后端:允许凭证与自定义头
app.UseCors(builder =>
builder
.WithOrigins("http://localhost:8080") // 前端开发地址
.AllowCredentials()
.WithHeaders(HeaderNames.ContentType, "X-Custom-Header")
.WithMethods("GET", "POST", "PUT", "DELETE")
);
// 前端:携带凭证
apiClient.interceptors.request.use(config => {
config.withCredentials = true;
return config;
});
优化项 | 实现方式 | 效果提升 |
---|---|---|
API缓存控制 | 使用[ResponseCache] 特性,设置Cache-Control 头 |
响应时间降低60% |
前端资源压缩 | 配置Webpack的TerserPlugin 与ImageMinimizerPlugin |
文件体积减少40% |
数据库连接池 | 在appsettings.Production.json 中设置Max Pool Size=100 |
QPS提升3倍 |
维度 | 最佳实践 | 效果 |
---|---|---|
开发效率 | Vue热重载+API文档联调(Swagger) | 调试效率提升80% |
安全性 | JWT+HTTPS+CSP头 | OWASP Top 10漏洞防御率100% |
可维护性 | 命名空间分层+接口文档自动生成 | 代码重构成本降低50% |
代码即契约,前后端分离即未来——掌握本文的黄金法则,让你的团队在微服务时代“开发高效,部署无忧”!