一、前言
前段时间,在项目基本功能开发完成后,想要将项目部署上线进行测试,结果刚部署上去就出现了下面的问题:网站首页可以访问,但是一刷新的时候就出现了页面报出404错误的问题,在这个问题解决后,发起网络请求获取数据时又出现了405错误。
二、404错误产生原因
1. 为什么我们刚进入网站首页时没问题,但一刷新就出现404呢?
出现该问题的原因在于当我们进入到网站后,一般路由会跳转到登陆页面之类的子路,或者我们登陆后进入其他子路由,这时我们的路由是通过前端JS来进行控制的的,并没什么问题,注意这时地址栏上的 url 很可能和我们最开始访问网站时输入的不一样了;那么一旦在此时刷新页面,在后台却没有与当前 url 相对应的页面,就会出现404问题。
2. 为什么在 vue 项目中,使用 hash 路由时没有这样的问题呢?
原因如下:例如当我们进入 www.xxx.com 时,我们会进入网站 index.html 页面,然后路由可能就会跳转到 www.xxx.com/#/login ,当我们刷新页面时, 被带入http请求的内容仅仅是 www.xxx.com 而不是www.xxx.com/#/login ,这是因为hash值不会被包括在http请求中,故而后台依旧返回 index.html 页面,然后由 js 来控制路由,页面刷新正常;但是,如果使用的 history 路由,那么带入 http 请求的内容就是 www.xxx.com/login ,而后台此时并没有对应的页面返回,故而出现404错误。
三、404错误解决办法
1. 修改 nginx 配置文件
修改 nginx .conf 配置文件,在合理的位置加上 try_files $uri $uri/ /index.html; 配置项即可,try_files 指令及 $uri 的涵义可以参考我的另一篇文章 juejin.cn/post/718803… 。
修改好配置文件后不要忘了重启 nginx 服务器: nginx -s reload 。
2. 使用 hash 路由
使用 hash 路由可以直接避免这个问题(如果项目原本就是使用的 history 路由,因为这个问题改成 hash 路由,此时显然不是一个好主意)。
四、405错误产生原因
在我最开始部署项目的时候,出现了405问题,我经过调试和查阅资料,判断应该是出现了跨域问题,可以配置反向代理来解决。这就引出了一些问题,是什么跨域,什么是反向代理呢?我们接着往下看。
1. 跨域及其解决方案
(1)跨域
跨域指的是一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的,通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。
(2)同源策略
同源策略是一个重要的安全策略,它用于限制一个 origin 的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。
同源策略限制以下行为:
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 和 JS对象无法获得
- AJAX 请求不能发送
注意:跨域限制是浏览器的机制,如果直接在服务端请求,是不会触发跨域限制的。
(3)同源定义
如果两个 URL 的 protocol、port (如果有指定的话) 和 host 都相同的话,则这两个 URL 是同源。
(4)跨域解决方案
- 通过 jsonp 跨域
- document.domain + iframe 跨域
- location.hash + iframe 跨域
- window.name + iframe 跨域
- postMessage 跨域
- 跨域资源共享(CORS)
- nginx 代理跨域
- node.js 中间件代理跨域
- WebSocket 协议跨域
就我个人而言相对比较喜欢 cors 和 nginx 反向代理这两种方式,它们也是现在主流的跨域解决方案。
2. 代理
(1)正向代理
特点:
- 正向代理需要主动设置代理服务器 ip 或者域名进行访问,由设置的服务器 ip 或者域名去访问内容并返回。
- 正向代理是代理客户端,为客户端收发请求,使真实客户端对服务器不可见。
用途:
- 突破访问显示:通过代理服务器,可以突破自身 ip 访问限制,访问国外网站等。
- 提高访问速度:通常代理服务器都设置一个较大的硬盘缓冲区,会将部分请求的响应保存到缓冲区中,当其他用户再访问相同的信息时,则直接由缓冲区中取出信息,传给用户,以提高访问速度。
- 隐藏客户端真实 ip:上网者可以通过正向代理的方法隐藏自己的 ip,免受攻击。
(2)反向代理
特点:
- 正向代理需要配置代理服务器,而反向代理不需要做任何设置。
- 反向代理是代理服务器,为服务器收发请求,使真实服务器对客户端不可见。
用途:
- 隐藏服务器真实 ip:使用反向代理,可以对客户端隐藏服务器的 ip 地址。
- 负载均衡:反向代理服务器可以做负载均衡,根据所有真实服务器的负载情况,将客户端请求分发到不同的真实服务器上。
- 提高访问速度:反向代理服务器可以对静态内容及短时间内有大量访问请求的动态内容提供缓存服务,提高访问速度。
- 提供安全保障:反向代理服务器可以作为应用层防火墙,为网站提供对基于 web 的攻击行为(例如DOS/DDOS)的防护,更容易排查恶意软件等。还可以为后端服务器统一提供加密和 SSL 加速(如 SSL 终端代理),提供 HTTP 访问认证等。
五、405错误解决办法
现在知道了问题来自哪里,也知道了什么是反向代理,我就照着之前已经部署过的项目的配置文件,修改当前的 .conf 文件,添加上 proxy_pass 配置,后面的 url 用后端服务的 ip,但是问题依旧没有解决,还是报 405 错误。 配置如下:
location /api/ { proxy_pass http://xx.xx.xxx.x:xxxx/; }
找了很久的 bug 后发现是 url 后多加了一个 / 导致的( / 根据实际情况决定要不要加,点击可参考),去掉多加的 / 后重启 nignx 服务器,问题解决。
上面解决了生产环境中的跨域问题,转念一想,为什么开发环境中没有出现跨域问题呢?去回顾了项目代码,然后看到 webpack 的 proxy 配置,如下:
proxy: {
'/api': {
target: 'http://xxx.xxx.x.xx:8000',
pathRewrite: { '^/api': '' },
changeOrigin: true,
},
target: 表示代理到的目标地址,即后端服务的地址。
pathRewrite:默认情况下 /api 会被写到目标地址去,检测接口中出现的 /api 只是我们用来检测转发的而已,在实际的请求中我们将它替换为''空字符串。
changeOrigin:用于控制请求头中的 host 值,默认是 ture ,则此时 host 值为 target 的值。
为什么这样的配置可以解决开发环境中的跨域问题呢?
proxy 实际上是利用了 http-proxy-middleware http 代理中间件,将请求转发给其他服务器。通过 proxy 代理请求后,会在浏览器与真实服务器之间添加一个代理服务器,本地发送请求时,中间代理服务器接收后转发给目标服务器,目标服务器返回数据,中间代理服务器将数据返回给浏览器。中间代理服务器与目标服务器之间不存在跨域问题。
参考文档:
developer.mozilla.org/zh-CN/docs/…
blog.csdn.net/qq_34402069…
juejin.cn/post/709532…
blog.csdn.net/weixin_4074…