遇到前端部署问题怎么办?nginx、端口、https域名怎么配置,跨域问题咋整,react/vue项目怎么部署,什么是反向代理,请您耐心往下看。本文通俗易懂,可操作,旨在抛砖引玉。要是帮到了您,还请顺便点个赞。

前言

前端部署,是让前端代码在服务器环境正常运行。而前端日常工作,主要还是业务代码开发,资源引用,前端路由配置等。至于部署,更多的是运维人员操作接触不多。但现实项目中,往往一部署到这些环境就出现各种各样的问题,如果我们有部署相关的理论、实践经验,面对问题就能更容易定位到问题,提高上线效率。

背景

当你兴致勃勃买了台服务器,然后规划着美好的未来,规划搭建平台。问题来了,前端项目如何部署(demo来自于Internet项目版权归各自所有)…

images/1.上线预期.png

预期的几个目标:

目录

按照从零起步的原则,按照以下目录来循序渐进

  • 1.服务器分类
  • 2.轻量强大的nginx
  • 3.前端服务管理工具-pm2
  • 4.解决跨域“问题”
  • 5.☆部署react/vue单页面静态项目
  • 6.实现https
  • 7.持续集成CI-自动化部署

1.服务器分类

1.1 应用服务器

专注于动态资源、解析高级开发语言编写的代码。前端服务一般基于解析JavaScript语言的nodejs搭建

  • JAVA:Tomcat、resin、jboss、weblogic 等
  • PHP:Apache等
  • .NET:IIS等
  • Nodejs:express、 koa、eggjs等

1.2 网关服务器

专注于静态资源、代理转发、负载均衡等

  • Nginx、Tengine等

2.轻量强大的Nginx

Nginx特性很多,前端常用一些特性,其他特性各大互联网公司经过大量实践已证明。关于nginx配置,主要就是配置nginx.conf以及修改后reload使配置生效。具体nginx下载与教程可以参照官网等。Nginx主要是修改配置文件以及生效。

2.1 简介

2.1.1 前端常用特性

  • 域名绑定
  • 静态资源
  • 反向代理
  • 支持https
  • 跨平台

2.1.2 其他特性

  • 负载均衡、高并发

2.1.5 nginx下载和目录说明

nginx官方网站:http://nginx.org/

nginx主要通过修改conf/nginx.conf配置文件,重启nginx程序生效实现服务器功能。

images/2.轻量强大的nginx-静态资源-nginx文件目录

1
2
3
4
5
6
7
8
9
// 重启使配置文件生效
// windows
.\nginx.exe -s reload

// linux/mac
nginx -s reload

// ps windows下强制结束nginx.exe进程命令
taskkill /f /t /im nginx.exe

2.2 实战配置

2.2.1 环境准备

  • nginx.org下载最新的nginx压缩包直接解压,windows/linux/mac下载对应的版本
  • 创建文件夹,windows下为如C盘根目录创建 c:/server;linux/mac可以在某个目录创建如根目录创建 /server

2.2.2 静态资源

首先,我们来实现js、png图片、css资源的静态资源配置。server文件夹下创建static文件夹,里面分别创建js、img、css文件夹并在对应文件夹放置对应格式的测试文件内容随意。最终访问路径和效果如下:

1
2
3
/static/js/js.js
/static/img/img.png
/static/css/css.css

images/2.轻量强大的nginx-静态资源-资源访问效果.png

2.2.3 nginx配置静态资源

找到nginx文件夹中的 conf/nginx.conf配置文件对应如下配置,配置完成后需要重启nginx,上面有如何重启,结束进程再次打开进程或者reload。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# nginx.conf文件找到server区域

server {
# nginx监听端口号,不能被其他应用占用
listen 80;

# nginx绑定的域名,本文用localhost
server_name localhost;

# 公共静态资源
location /static/ {
#root C:/server/;
alias C:/server/static/;
autoindex on;
# 是否启用目录索引
#autoindex on;
}
}

2.2.4 目录索引

以上配置有个 autoindex on,如果配置了如果访问的是目录,则展示目录索引,如果关闭则展示403 Forbidden。一般为了服务器安全不被探测,都是关闭索引目录。

开启索引效果

开启索引效果

关闭索引效果

关闭索引效果

2.2.5 附:nginx静态站点

配置三个静态web站点备用。配置方法很简单,C:/server创建两个文件夹,立马分别有个index.html文件。nginx.conf增加以下配置后重启nginx生效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server {
listen 10001;
server_name localhost;
root C:/server/siteA;
index index.html index.htm;
}
server {
listen 10002;
server_name localhost;
root C:/server/siteB;
index index.html index.htm;
}
server {
listen 10003;
server_name localhost;
root C:/server/siteB;
index index.html index.htm;
location / {
add_header X-Frame-Options SAMEORIGIN;
}
}

至此,任务5静态资源任务达成。恭喜您已经具备使用nginx搭建静态web站点和静态文件服务的能力了,具体相关其他配置可以自行深入研究。

3 部署前端服务-pm2

前端服务-即前端使用如基于nodejs平台下能够有独立运行访问的web服务等。如nextjs、express、koa、eggjs等前端应用服务器。

pm2是什么

众所周知,我们一般启动前端服务,开启一个bash,然后执行如npm start服务器愉快的跑起来,但如果有多个服务,就必须要打开多个,一般在服务器环境你只有一个bash端口必须得后台运行,如何后台运行nodejs服务,以及方便的管理各个nodejs服务的暂停、重启、销毁,我们得需要一个能够管理他们的软件。pm2应运而生。

pm2工具:把nodejs服务变为后台服务,统一管理(常用于服务器环境、控制台命令环境)

详见pm2官方文档 https://www.npmjs.com/package/pm2, https://pm2.keymetrics.io/docs/usage/application-declaration/

安装

1
npm install pm2 –g

常用命令

  • pm2 start pm2.json #根据pm2.json配置方式启动进程
  • pm2 list, pm2 status #列出当前所有pm2管理列表
  • pm2 stop 0 #停用指定id的服务
  • pm2 delete 0 #删除指定id的服务
  • pm2 restart 0 #重启指定id的服务

实战

我们根据上述最开始官方项目启动nextjs、koa2的nodejs服务,(以前我们是执行npm run start,本地模拟可以直接先启动),现在如果需要pm2改造

先看运行效果:

1.基于nextjs的nodejs服务:127.0.0.1:12111

部署前端服务-nextjs

2.基于koa2的nodejs服务:127.0.0.1:18000

部署前端服务-koa

3.pm2 list列出所有pm2托管的node服务

.部署前端服务-pm2

配置

最终我们是直接通过目录下的start.bat/start.sh执行pm2命令。最终为了间接执行到npm start的命令,给予pm2进行托管

windows下的pm2存在一些问题,需要通过间接方式执行npm命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 1.koa/nextjs项目根目录增加start.bat / start.sh,内容为pm2的命令
pm2 start ecosystem.config.js

// 2.创建ecosystem.config.js配置文件,以下已沟通。详细其他参数可参照pm2官网查看具体配置. https://pm2.keymetrics.io/docs/usage/application-declaration/
module.exports = {
apps: [{
name: 'MyKoa',
script: 'start.js',
args: 'one two',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
}]
};

// 3.创建start.js
const cmd = require('node-cmd');
cmd.run('npm run start');

// 4.package.json配置,需要项目安装node-cmd的包,具体npm run start就是项目中如何启动nodejs服务根据具体项目来
{
"start": "node bin/development.js",
}

至此,您已经本地运行了两个前端node服务。任务1、2完成50%.

4.解决跨域”问题”

4.1跨域——“正常”的安全策略

我们两个node都启了,你一定会立马就想让nextjs的fetch请求来请求koa的api服务,结果跨域了。。

场景一、XMLHttpRequest、fetch等同源限制

浏览器出于安全当访问不同端口、域名默认情况下是不允许的,也是出于安全。如果谁都能互相随便调用岂不是没有了安全可言。

4.解决跨域问题-fetch同源限制

场景二、iframe跨域引用问题

一般出于安全,页面的HTTP请求的Response头部设置了X-Frame-Options:sameorigin,防止页面被其他站点内嵌。

解决跨域问题-iframe跨域问题

4.2nginx解决方案-反向代理

4.2.1 什么是反向代理

一句话解释:客户端请求服务器,服务器接收转发给其他服务器获得内容,再传给客户端。

反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。

正向代理:意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。

4.2.2 先看nginx的预期效果

当localhost访问 /api/test/list成功转发到koa服务(127.0.0.1:12111)返回数据

解决跨域问题-nginx反向代理

4.2.3 nginx配置反向代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1.首页为nextjs的web server,便于SEO优化。访问所有优先转发给nextjs服务
location / {
proxy_pass http://127.0.0.1:12111/;
proxy_redirect off;
proxy_set_header Host $proxy_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Via "nginx";
}

# 2.转发/api请求给前端koa服务器
location /api {
proxy_pass http://127.0.0.1:18000/api;
proxy_redirect off;
proxy_set_header Host $proxy_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Via "nginx";
}

4.3 iframe跨域解决

iframe跨域一般还是通过服务器设置response header头。分为旧版本浏览器和新版本浏览器。旧版本:X-Frame-Options,新版本:Content-Security-Policy。可参考:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy

nginx下具体设置如下,可以指定对应可跨域iframe访问的域名

1
2
3
4
5
6
7
8
9
10
11
12
13
# 被内嵌iframe web设置
server {
listen 10004;
server_name localhost;
root C:/server/siteB;
index index.html index.htm;
location / {
# 旧版本
add_header X-Frame-Options "ALLOW-FROM http://localhost";
# 新版本使用csp
# add_header Content-Security-Policy "frame-ancestors 'self’ http://localhost";
}
}

4.解决跨域问题-iframe跨域问题-设置头

4.4 http报头跨域

一般为开发阶段的mock server,或者设置允许跨域的域名.这样,我们可以直接访问mock数据

解决跨域问题-iframe跨域问题-http报头跨域设置

解决跨域问题-iframe跨域问题-http报头跨域效果

☆5.部署react/vue单页面静态项目

本章节作为react/vue开发者必备部署知识,因为你的代码始终是要发布的,出了啥问题你就能很快定位(甩锅)问题所在。

5.1 单页面应用核心问题

部署单页面应用项目我们核心思考的问题:服务器端路由与静态单页面应用路由的转换过程

部署react、vue单页面静态应用-服务器端路由与静态单页面应用路由的转换过程思考

5.2 nginx配置单页面应用

我们进行分析:当访问url时,先访问nginx服务器,nginx路由判定后给前端路由托管。我们得出以下的配置:访问静态资源子路径下的所有路由均转发给静态资源的index.html文件。实现后端路由转换为前端路由。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1.create-react-app静态项目
location /react-app {
# 路径
alias C:/server/create-react-app-antd/build;
# 默认首页
index index.html;
# 访问不到资源后的处理
try_files $uri $uri/ /react-app/index.html;
}

# 2.vue静态项目
location /vue-app {
alias C:/server/vueapp/build;
index index.html;
try_files $uri $uri/ /vue-app/index.html;
}

问题一:原始项目直接配置完成无法访问,资源报错

vue-cli项目配置

首先,如果直接从vue官网的命令安装依赖,执行npm run build,配置完是会报错的。

部署react、vue单页面静态应用-vue或react原始项目直接build会报错

问题原因:css/js资源引用路径没有引用到,解决方法1改成相对路径访问

部署react、vue单页面静态应用-单页面静态的前端资源需要变为相对路径

修改后重新编译,成功访问

部署react、vue单页面静态应用-vue静态页面完成部署

react项目配置

默认create-react-app-antd项目npm run build后配置完会出现资源无法访问的问题。原因,项目都是绝对路径访问资源。

部署react、vue单页面静态应用-react默认项目路径报错

react项目里面由于脚手架配置读取package.json的homepage项为根路径

部署react、vue单页面静态应用-react项目修改资源路径

重新打包编译后正常访问。这里稍作修改,项目内容增加了路由跳转,这样好测试静态资源路由功能。

部署react、vue单页面静态应用-react项目正确配置完成后预览效果

问题二:我上线出现了点击上面react项目首页 http://localhost/react-app/点击链接跳转 http://localhost/react-app/test能打开,但我刷新页面报nginx404了。(很多小伙伴都出现了发布后出现这个情况明明默认都能点,刷新页面后就打不开了报404)

部署react、vue单页面静态应用-react项目正常路由跳转到test子路由

子路由刷新页面后404

部署react、vue单页面静态应用-react项目子路由刷新后报404

why刷新报错?

冷静思考,根源还是来自于前后端路由的转换问题,还记得上面配置行(3行)中重要的一句话:try_files 尝试文件,也就是说服务器找不到文件你得告诉怎么处理跳转到哪儿。也就定位到问题:try_files $uri $uri/ /react-app/index.html;这句异常处理如果不加就会导致刷新访问不到文件的问题。
回味一下配置:访问不到的时候转发给下面的index.html页面,index.html无缝对接前端的路由。问题解决。

1
2
3
4
5
6
location /react-app {
alias C:/server/create-react-app-antd/build;
index index.html;
# 下面这句话就起作用了很关键
try_files $uri $uri/ /react-app/index.html;
}

至此,您已具备单页面应用项目的能力,判定资源访问路径,而且还能够排查出部署刷新页面报404这样的经典问题。任务3,4react/vue的静态子项目成功部署。

6 https访问

至此,上述的几个应用系统已经完全贯通运作。但http不是不安全吗,我需要用https让网站能够安全访问。

6.1 https基于ssl证书访问关键要素

  • 申请证书、秘钥(openssl工具)
  • 配置nginx

其实本地环境是可以通过命令行工具生成秘钥和证书,用来测试https

nginx 本地https秘钥可参考文档:https://www.cnblogs.com/isylar/p/10002117.html

先看效果:https访问后端口号变为了443

https访问-成功配置效果

nginx配置如下:最关键的就是pem证书和key的生成。按照上面文档本地就可以生成,网上也有很多关于https证书秘钥生成教程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 server {
listen 443 ssl;
server_name localhost;
index index.html index.htm index.php;
root C:/lc/server;
# pem证书路径
ssl_certificate C:/lc/work/proj/https/server/server.pem;
# pem证书路径
ssl_certificate_key C:/lc/work/proj/https/server/server.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {

}
}

问题:本地刚配置https访问后浏览器提示不安全的连接

https访问-本地刚配置好提示不安全

解答:由于浏览器https是需要经过合法CA办法的证书,我们自己配置的并非经过证书颁发机构。点击继续前往还是能够本地访问到。

如何强制http请求转为https请求

nginx配置为:80端口访问后rewrite所有请求为https

1
2
3
4
5
6
server {
listen 80;
server_name localhost;
# 强制使用https
rewrite ^(.*)$ https://$host$1 permanent;
}

7.持续集成CI-自动化部署

7.1核心思想

  • 具有执行服务器端脚本能力
  • 通过web等UI界面方便操作
  • 支持通过如git web hook等触发式构建

7.2常用软件

7.3本地写个自动更新代码自动打包的脚本

我们在刚刚 C:/server/create-react-app-antd下新建build.sh和build.bat,用来执行后自动拉取代码以及自动执行编译打包

build.bat

1
2
3
4
5
echo start build...
echo running step 1.git pull
git pull
echo running step 2.npm run build
npm run build

build.sh

1
2
3
4
5
6
#!/usr/bin/env bash
echo start build...
echo running step 1.git pull
git pull
echo running step 2.npm run build
npm run build

收尾

能看到这里,真心感谢您的耐心,是不是有种醍醐灌顶,原来前端部署一篇就够了。有了这些,我们在以后的前端上线部署不再是盲区,又能够快速定位问题。
结尾还是那句话:要是帮到了您,还请顺便点个赞,谢谢(90度鞠躬)。