Springboot+Vue在开发和部署相关问题解决
Springboot端的配置添加一个跨域请求的配置类import org.springframework.context.annotation.Configuration;import org.springframework.web.cors.CorsConfiguration;import org.springframework.context.annotation.Bean;impo...
Springboot
+Vue
在开发和部署相关问题解决
一、可能遇到的问题:
- 跨域
- 路由使用
hash
或者history
- 打包时的配置(
history
)的情况 - 部署问题
- 部署之后出现跨域
- 刷新之后404
Nginx
如何进行端口代理
接下来通过我采坑的经历,进行一一详述!
二、跨域问题
针对跨域我们需要对Springboot
和Vue
两部分进行处理。
2.1. Sprigboot
对于跨域的处理
Springboot
这个方面可能有很多中方法:
- 我们可以添加一个拦截器设置请求的
header
头进行处理 - 使用
@CrossOrigin
对某一个接口进行跨域设置 - 使用手工设置
HttpServletResponse
对象添加响应头
下面的是我针对Springboot
的跨域的处理
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* @author 墨龙吟
* @version 1.0.0
* @ClassName CorsConfig.java
* @Description 跨域配置
* @createTime 2019年10月25日 - 15:58
*/
@Configuration
public class CorsConfig {
@Bean
public FilterRegistrationBean corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 放行哪些原始域
config.addAllowedOrigin("*");
// 是否发送cookie信息
config.setAllowCredentials(true);
// 放行的请求方式
config.addAllowedMethod("*");
// 放行的头部信息
config.addAllowedHeader("*");
// 添加映射路径
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
// 将新的CorsFilter注册到FilterRegistrationBean中
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(configSource));
// 设置优先级
bean.setOrder(0);
return bean;
}
}
这样我们的关于后端的跨域基本上就完成了。
2.2. Vue
端的跨域设置
在我们开发的时候上面针对Springboot
的跨域配置。我们已经可以开发了,但是在我们要部署到服务器上的时候还是出现跨域问题,所以我这里直接就弄好就可以了。
2.2.1. 首先是对vue.config.js
文件配置
// vue.config.js
const path = require('path');
function resolve(dir) {
return path.join(__dirname, dir)
}
// 项目的主要配置文件
module.exports = {
// 开发测试的是时候使用 publicPath: '/' ; 打包部署的时候 使用 '/blog/'
// publicPath: '/blog/',
publicPath: '/',
outputDir: 'dist',
assetsDir: 'static'
devServer: {
port: 8080,
// 是上线所需的额外配置,本地测试的需要需要注释掉
// publicPath: '/',
proxy: {// 配置跨域
'/api': {
// 这里后台的地址模拟的;应该填写你们真实的后台接口
target: 'http://localhost:9999/api',
ws: true,
// 允许跨域
changOrigin: true,
pathRewrite: {
// 请求的时候使用这个api就可以
'^/api': ''
}
}
}
}
}
2.2.2. 修改路由文件
import Vue from 'vue'
import Router from 'vue-router'
import Cookies from 'js-cookie'
Vue.use(Router)
let router = new Router({
// 切换路由为history模型
mode: 'history',
// 基础路径,/blog/ 这里和vue.config.js里面publicPath相对应。
base: '/blog/',
routes: [
{
// ...
}
]
});
export default router
2.2.3. 配置axios
中的baseURL
一般都是要写一个关于axios
和get
、post
分装的工具类,我们修改axios
的默认配置信息
axios.defaults.baseURL = 'http://localhost:9999/api';
axios.defaults.withCredentials = true;
三、路由模型的选择和刷新404问题
3.1. 两种路由的区别
路由使用hash
或者history
,这两中区别如下:
hash
—— 即地址栏 URL 中的#
符号(此 hash 不是密码学里的散列运算)。
比如这个 URL:http://www.abc.com/#/hello
,hash 的值为#/hello
。它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。history
—— 利用了HTML5 History Interface
中新增的pushState()
和replaceState()
方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的back
、forward
、go
的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
3.2. 两种路由的优缺点:
-
Hash
路由:优点:
- 实现简单,兼容性好(兼容到
ie8
) - 绝大多数前端框架均提供了给予
hash
的路由实现 - 不需要服务器端进行任何设置和开发
- 除了资源加载和
ajax
请求以外,不会发起其他请求
缺点:
- 对于部分需要重定向的操作,后端无法获取
hash
部分内容,导致后台无法取得url
中的数据,典型的例子就是微信公众号的oauth
验证 - 服务器端无法准确跟踪前端路由信息
- 对于需要锚点功能的需求会与目前路由机制冲突
- 实现简单,兼容性好(兼容到
-
History
路由优点:
- 对于重定向过程中不会丢失
url
中的参数。后端可以拿到这部分数据 - 绝大多数前段框架均提供了
browser
的路由实现 - 后端可以准确跟踪路由信息
- 可以使用
history.state
来获取当前url
对应的状态信息
缺点:
- 兼容性不如
hash
路由(只兼容到IE10
) - 需要后端支持,每次返回
html
文档
- 对于重定向过程中不会丢失
3.3. 使用History
部署的时候刷新404问题解决:
因此可以说,hash
模式和history
模式都属于浏览器自身的特性,Vue-Router
只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由。
我们使用history
的时候是没有#
虽然美观,但是会有问题 **不怕前进,不怕后退,就怕刷新,F5,(如果后端没有准备的话),因为刷新是实实在在地去请求服务器的。**这里就需要我们在服务器里面配置一下
我们使用Springboot
项目所以正常都会安装Tomcat
服务器,当我们把Vue
项目打包之后放到webapps
。
这里的项目目录blog
也是和我们上面配置的相对应的。
在我们的项目里面添加一个WEB-INF
目录。里面添加web.xml
,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1" metadata-complete="true">
<display-name>Router for Tomcat</display-name>
<error-page>
<error-code>404</error-code>
<location>/index.html</location>
</error-page>
</web-app>
这样子,我们再次刷新之后就不会出现404的问题了。
四、Nginx
代理的问题
我们先从安装开始!
4.1. Centos8
安装Nginx
下载Nginx
地址: http://nginx.org/en/download.html,下载最新的版本1.17.9
!
一般来说我们自己安装软件的话,一般都放到/opt
目录里面。将安装包拷贝到/opt
目录之后创建一个nginx
的目录,执行解压。
# 创建nginx目录 解压安装包 然后进入解压后的目录
mkdir nginx && tar -zxvf nginx-1.17.9.tar.gz && cd nginx-1.17.9
接着安装Nginx
所需要的一些依赖
yum install -y pcre pcre-devel zlib zlib-devel openssl openssl-devel
然后就进行配置、编译和安装了
# /opt/nginx 就是安装路径,这个看你是安装到哪个目录自己配置吧
./configure --prefix=/opt/nginx --with-http_stub_status_module --with-http_ssl_module && make && make install
最后还需要将nginx
添加到服务里面,方便我们去通过systemctl
启动和停止。
对于systemctl
相关的serivce
文件一般都是在/etc/systemd/system/
目录里面的,但是,里面存放的大部分文件都是符号链接,指向目录/usr/lib/systemd/system/
,真正的配置文件存放在/usr/lib/systemd/system/
目录的。所以哪个目录都可以,看自己高兴吧!
创建一个nginx.service
文件,里面的内容如下:
[Unit]
Description=Nginx - high performance web server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
ExecStart=/opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf
ExecReload=/opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf -s reload
ExecStop=/opt/nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=multi-user.target
其他的地方都不需要配置,只需要将 /opt/nginx/sbin/nginx
的执行文件的位置和/opt/nginx/conf/nginx.conf
配置文件的位置替换成你自己的安装位置就可以了!
最后让服务生效,启动nginx
# 刷新systemctl
systemctl daemon-reload
# 将nginx添加到开机自启
systemctl enable nginx
# 将nginx启动
systemctl start nginx
# 将nginx停止。每次修改conf文件都是重启nginx
systemctl stop nginx
4.2. 配置Nginx
这里的配置相对来说,就是对nginx
,日后将会针对对个项目配置,那样的话都写在conf
文件会很乱,也不方便管理,我们可以将每个项目都创建一个conf
文件,然后加载入nginx
中。
首先需要在nginx
中添加一行配置:
include /opt/nginx/webapps/*.conf;
添加的位置:
这样就会将/opt/nginx/webapps/
下所有conf
后缀的文件都加载在nginx
启动的时候!
4.3. 配置端口转发
接着回归我们之前的问题,部署之后我们访问是需要带着端口号的,所有我们可以使用Nginx
做端口转发。我们在/opt/nginx/webapps/
下添加一个blog.conf
文件,具体配置如下:
server {
# 监听80端口
listen 80;
server_name localhost;
location / {
root /opt/tomcat9/webapps/blog/;
index index.html;
try_files $uri $uri/ @router;
index index.html;
}
location @router {
rewrite ^.*$ /index.html last;
}
# 我们在上面vue上配置的项目名现在还有用处。通过/blog就可以转发到我们要的端口
location /blog {
# root /opt/tomcat9/webapps;
# try_files $uri $uri/ /blog/index.html;
proxy_pass http://服务器IP地址:8080/blog;
}
}
五、Tomcat
安装配置
最后我在说一下Tomcat
在Centos
下的安装配置,其实安装很简单,就是下载安装包,解压就可以启动了,重点是要添加systemclt
系统服务中,还是在我们4.1
中所说,在/usr/lib/systemd/system/
或者/etc/systemd/system/
中添加一个tomcat.service
的文件。
[Unit]
Deascription=Tomcat 9 servlet container
After=network.target
[Service]
Type=forking
# 这里添加你Centos中jdk的jre目录位置
Environment="JAVA_HOME=/opt/java8/jre"
Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom"
Environment="CATALINA_BASE=/opt/tomcat9/"
Environment="CATALINA_HOME=/opt/tomcat9"
# 配置一下运行的内存大小
Environment="CATALINA_OPTS=-Xms256M -Xmx512M -server -XX:+UseParallelGC"
# 启动和停止的命令
ExecStart=/opt/tomcat9/bin/startup.sh
ExecStop=/opt/tomcat9/bin/shutdown.sh
[Install]
WantedBy=multi-user.target
最后还是和上面一下执行:
# 刷新systemctl
systemctl daemon-reload
# 将tomcat添加到开机自启
systemctl enable tomcat
# 将tomcat启动
systemctl start tomcat
# 将tomcat停止
systemctl stop tomcat
六、产生跨域的原因
在上面我们一直在寻找跨域的解决问题,但是为什么会产生跨域呢,我们需要了解下,做到知其然而知其所以然!
6.1. 同域策略
当我们请求的时候会出现这样的问题:
这个就是浏览器的同源策略的有关系了!官方解释很官方,我用大白话解释一下吧,简单来说:当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指的是这样的一个概念:我们认为若协议 + 域名 + 端口号均相同,那么就是同域,不是同域的就是跨域了。
我们上面接口的地址是:localhost:9999
但是vue
的地址是localhost:8080
这样就不符合协议 + 域名 + 端口号均相同,这样就不在同一个域里面就是出现跨域的问题了。
我们经常出现的问题是因为同域策略中一条:Cookie
和XMLHttprequest
层面的同源策略:禁止 Ajax
直接发起跨域HTTP
请求(其实可以发送请求,结果被浏览器拦截,不展示),同时Ajax
请求不能携带与本网站不同源的 Cookie
。
6.2. 跨域会出现的安全问题
浏览器会对上面提到的跨域请求作出限制。浏览器之所以要对跨域请求作出限制,是出于安全方面的考虑,因为跨域请求有可能被不法分子利用来发动 CSRF
攻击。
通俗来说CSRF
攻击就是攻击者盗用了你的身份,以你的名义发送而已请求。
CSRF
能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号等等,如果你的个人隐私泄露那么财产安全就更危险了。
6.2. Jsonp
和cors
在安全上来说同源限制是必要的,但有时同源策略会对我们开发造成影响,为了避免开发的限制,有多种方式可以绕开同源策略,下面介绍的是经常使用的 Jsonp
, cors
方法。
6.2.1. Jsonp
方法
Jsonp
是一种非官方的跨域数据交互协议,只支持get
方法,限制很多,但是可以再一些很古老的浏览器中使用,现在使用的也很少了,我们就不做过多的深究了。
6.2.2. cors
方法
CORS
简称:跨源资源共享 Cross-Origin Resource Sharing
是一个新的 W3C
标准,它新增的一组HTTP首部字段,允许服务端其声明哪些源站有权限访问哪些资源。简单来说,它允许浏览器向声明了CORS
的跨域服务器,发出 XMLHttpReuest
请求,从而克服 Ajax
只能同源使用的限制。
我们在使用的时候,浏览器必须首先使用 optioin
方法发起一个预检请求,从而获知服务端是否允许该跨域请求,在服务器确定允许后,才发起实际的HTTP
请求。
下面我们了解下新增的header
头信息:
Access-Control-Allow-Origin
:响应首部中可以携带这个头部表示服务器允许哪些域可以访问该资源。Access-Control-Allow-Methods:
该首部字段用于预检请求的响应,指明实际请求所允许使用的HTTP方法。Access-Control-Allow-Headers:
该首部字段用于预检请求的响应。指明了实际请求中允许携带的首部字段。Access-Control-Max-Age:
该首部字段用于预检请求的响应,指定了预检请求能够被缓存多久。Access-Control-Allow-Credentials:
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie
。默认情况下,Cookie
不包括在CORS
请求之中。设为true
,即表示服务器明确许可,Cookie
可以包含在请求中,一起发给服务器。Origin:
该首部字段表明预检请求或实际请求的源站。不管是否为跨域请求,Origin字段总是被发送。
我们在Springboot
上面的CORS
过滤器配置,也是在设置这些头:
好了!就这样了,在项目部署的时候遇到的坑就这些了。
欢迎关注我的公众号!
更多推荐
所有评论(0)