背景
本节的目标是在服务器上一个前端应用,一个后端应用,并完成前后端的交互。具体目标为:
- 能访问到前端页面
- 能调通一个接口
约定
- 前后端应用都使用docker部署
- 前端使用vue3 + vite,使用nginx作为web服务器,后端使用express
- 前端运行在3000端口,后端运行在4000端口。
- 前端路由加上/blog前缀,后端接口加上/api前缀,线上环境使用nginx转发完成接口交互,开发环境使用server.proxy完成接口交互。
前端代码:blog-app-fe
后端代码:blog-app-backend
后端应用部署
编写一个接口
编写一个简单的get接口,用于后面接口测试
const express = require("express");
const app = express();
const port = 4000;
app.get("/blogInfo", (req, res) => {
const userInfo = {
message: "Hello Blog",
};
res.json(userInfo);
});
app.listen(4000, () => {
console.log(`Example app listening on port ${4000}`);
});
编写docker file
# 使用官方 Node.js 镜像作为构建基础镜像
FROM node:18.17.1 AS builder
# 安装 pnpm
RUN npm install -g pnpm@8.7.0
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 pnpm-lock.yaml(如果有的话)到工作目录
COPY package*.json pnpm-lock.yaml* ./
# 安装应用依赖
RUN pnpm install
# 复制应用源代码到工作目录
COPY . .
# 暴露端口 4000
EXPOSE 4000
# 启动应用程序
CMD ["npm", "run", "start"]
完成部署
- 本地构建镜像并推送到docker hub
# m系列芯片需要指定架构 docker buildx build --platform linux/amd64 -t mhhongfe/blog-app-backend:1.0 --push . # 非m系列芯片 docker build -t mhhongfe/blog-app-backend:1.0 --push . - 服务器上拉取镜像并运行
# 如果之前有同名容器,需要先删掉 docker ps docker stop 容器ID docker rm 容器ID # pull镜像 docker pull mhhongfe/blog-app-backend:1.0 docker run -p 4000:4000 mhhongfe/blog-app-backend:1.0 - 访问接口 访问serverIp:4000/blogInfo,显示{ message: "Hello Blog", }
后端服务部署成功!
阿里云的安全组需要开发4000端口
前端应用部署
前端路由增加/blog前缀
import { createWebHistory, createRouter } from 'vue-router'
import HomeView from '../pages/home/index.vue'
import AboutView from '../pages/about/index.vue'
const routes = [
{ path: '/', redirect: '/home' },
{ path: '/home', component: HomeView },
{ path: '/about', component: AboutView },
]
// 前端路由,使用blo前缀
const router = createRouter({
history: createWebHistory('blog'),
routes,
})
export default router;
测试接口
在home页面,点击发送请求,如果接口请求正常,会在alert中显示返回值
<template>
<div>
<span>Home页面</span>
<div>
<button @click="handleClick">发起请求</button>
</div>
</div>
</template>
<script setup lang= "ts">
async function handleClick() {
const res = await fetch('/api/blogInfo').then(res => res.json());
alert(res.message);
}
</script>
<style scoped>
</style>
配置nginx
项目根目录增加nginx.conf,加入如下内容:
# 全局上下文
worker_processes 1; # 设置工作进程数
# 事件块
events {
worker_connections 1024; # 设置每个工作进程的最大连接数
}
# HTTP 块
http {
include mime.types;
default_type application/octet-stream;
# 服务器块
server {
listen 80;
server_name localhost;
# 根目录的静态文件
location / {
root /usr/share/nginx/html;
try_files $uri /index.html; # 确保单页面应用的路由正常工作
}
# 如果需要其他处理
location /api/ {
proxy_pass http://serverIp:4000/; # 替换成真实的ip
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
- /api配置,具有这个前缀的请求都转发到后端服务
- /配置,没有匹配/api的都会在/usr/share/nginx/html目录下找对应的资源,如果没找到就显示index.html
- 这样配置可以解决访问localhost:80/正常显示,localhost:80/home显示nginx404的问题
配置docker
在项目根目录下增加Dockerfile
# 使用官方 Node.js 镜像作为构建基础镜像
FROM node:18.17.1 AS builder
# 安装 pnpm
RUN npm install -g pnpm@8.7.0
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 pnpm-lock.yaml(如果有的话)到工作目录
COPY package*.json pnpm-lock.yaml* ./
# 安装应用依赖
RUN pnpm install
# 复制应用源代码到工作目录
COPY . .
# 构建应用
RUN pnpm run build
# 使用 Nginx 镜像作为生产环境镜像
FROM nginx:alpine
# 复制自定义 Nginx 配置文件
COPY nginx.conf /etc/nginx/nginx.conf
# 将构建产物从 /app/dist 复制到 Nginx 的默认服务目录
COPY --from=builder /app/dist /usr/share/nginx/html
# 暴露端口 80
EXPOSE 80
# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]
对应nginx的配置,把构建产物dist都放在/usr/share/nginx/html目录下,这样不管是页面还是图片等其他资源都能顺利找到。
完成部署
-
本地构建镜像并推送到docker hub。
# m系列芯片需要指定架构 docker buildx build --platform linux/amd64 -t mhhongfe/blog-app-fe:1.0 --push . # 非m系列芯片 docker build -t mhhongfe/blog-app-fe:1.0 --push . -
服务器上拉取镜像并运行
docker pull mhhongfe/blog-app-fe:1.0 # 程序在容器内的80端口运行,容器在宿主机的3000端口运行 docker run -p 3000:80 mhhongfe/blog-app-fe:1.0 -
访问页面
访问服务器ip:3000/blog/home,页面显示正常 -
测试接口
接口调用正常
部署完成!
总结
目前完成了前后端各自的应用部署,与接口的交互,之后只需要不断完善前后端功能即可。