整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

vue项目本地开发完成后部署到服务器后报404是什么

vue项目本地开发完成后部署到服务器后报404是什么原因呢?

ue路由配置:

const router=new VueRouter({
  base: process.env.BASE_URL,
  //hash模式下部署到服务器访问没问题,history就不行,需要在服务器上配置
  mode: 'history',
  routes
})

vue.config.js配置:

module.exports={
  lintOnSave: false,
  publicPath: process.env.VUE_APP_PATH,
  // publicPath : process.env.NODE_ENV==='production' ? './' : '/',
  outputDir: 'dist',
  devServer: {
    disableHostCheck: true,
    // overlay: { // 让浏览器 overlay 同时显示警告和错误
    //   warnings: true,
    //   errors: true
    // },
    https: false, // https:{type:Boolean}
    open: false, //配置后自动启动浏览器
    hotOnly: true, // 热更新
    proxy: { //配置多个代理
      "/api": {
        target: "http://192.168.2.241",
        changeOrigin: true,
        ws: true, //websocket支持
        secure: false,
      },
    }
  },
}

404报错原因:

当我们设置了mode为history时,当前端发送路径给服务端时,服务端根本就不认识省去#的url,所以返回给我们404,因为vue是单一页面所有的页面都在index.html中,vue是用js来切换页面的,具体的解释看vue官网

解决办法:

nginx服务器修改

location / {
  if (!-e $request_filename) {
    rewrite  ^(.*)$ /index.html?s=/$1  last;
    break;
  }
}

一、如何部署

前后端分离开发模式下,前后端是独立部署的,前端只需要将最后的构建物上传至目标服务器的web容器指定的静态目录下即可

我们知道vue项目在构建后,是生成一系列的静态文件

常规部署我们只需要将这个目录上传至目标服务器即可

// scp 上传 user为主机登录用户,host为主机外网ip, xx为web容器静态资源路径
scp dist.zip user@host:/xx/xx/xx

web容器跑起来,以nginx为例

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
  }
}

配置完成记得重启nginx

// 检查配置是否正确
nginx -t 

// 平滑重启
nginx -s reload


操作完后就可以在浏览器输入域名进行访问了

当然上面只是提到最简单也是最直接的一种布署方式

什么自动化,镜像,容器,流水线布署,本质也是将这套逻辑抽象,隔离,用程序来代替重复性的劳动,本文不展开

二、404问题

这是一个经典的问题,相信很多同学都有遇到过,那么你知道其真正的原因吗?

我们先还原一下场景:

  • vue项目在本地时运行正常,但部署到服务器中,刷新页面,出现了404错误

先定位一下,HTTP 404 错误意味着链接指向的资源不存在

问题在于为什么不存在?且为什么只有history模式下会出现这个问题?

为什么history模式下有问题

Vue是属于单页应用(single-page application)

SPA是一种网络应用程序或网站的模型,所有用户交互是通过动态重写当前页面,前面我们也看到了,不管我们应用有多少页面,构建物都只会产出一个index.html

现在,我们回头来看一下我们的nginx配置

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
  }
}


可以根据 nginx 配置得出,当我们在地址栏输入 www.xxx.com 时,这时会打开我们 dist 目录下的 index.html 文件,然后我们再跳转路由进入到 www.xxx.com/login

关键在这里,当我们在 website.com/login 页执行刷新操作,nginx location 是没有相关配置的,所以就会出现 404 的情况

为什么hash模式下没有问题

router hash 模式我们都知道是用符号#表示的,如 website.com/#/login, hash 的值为 #/login

它的特点在于:hash 虽然出现在 URL 中,但不会被包括在内 HTTP 请求中,对服务端完全没有影响,因此改变 hash 不会重新加载页面

hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 website.com/#/login 只有 website.com 会被包含在请求中 ,因此对于服务端来说,即使没有配置location,也不会返回404错误

那么vue-router的hash模式和histroy模式有什么区别呢?

1、hash模式url带#,histroy模式url不带#

2、hash模式解决了通过http请求来切换页面,改变路径可以直接改变页面,无需进行网络请求,这叫前端路由,在hash模式下改变的是#中的信息,

history模式,可以前进和后退,但是不能刷新页面,刷新之后就会报错。如果后端没有对路由地址进行相应的处理,那么就会报404的错。

3、hash浏览器支持率比较好,支持低版本的浏览器,但history的方法只支持部分浏览器。


解决方案

看到这里我相信大部分同学都能想到怎么解决问题了,

产生问题的本质是因为我们的路由是通过JS来执行视图切换的,

当我们进入到子路由时刷新页面,web容器没有相对应的页面此时会出现404

所以我们只需要配置将任意页面都重定向到 index.html,把路由交由前端处理

nginx配置文件.conf修改,添加try_files $uri $uri/ /index.html;

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
    try_files $uri $uri/ /index.html;
  }
}


修改完配置文件后记得配置的更新

nginx -s reload

这么做以后,你的服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件

为了避免这种情况,你应该在 Vue 应用里面覆盖所有的路由情况,然后再给出一个 404 页面

const router=new VueRouter({
  mode: 'history',
  routes: [
    { path: '*', component: NotFoundComponent }
  ]
})


关于后端配置方案还有:Apachenodejs等,思想是一致的,这里就不展开述说了

给大家分享我收集整理的各种学习资料,前端小白交流、学习交流,也可以直接问我,我会组织大家一起做项目练习,帮助大家匹配一位学习伙伴互相监督学习-下面是学习资料参考。

前端学习交流、自学、学习资料、新手入门教程,自学教程等推荐

户反映:说自己的网站走nginx代理后,打开空白。直接IP加地址访问是好的(http://ip:port)

故障排查

1、打开chrome浏览器,访问了下,访问情况真是客户描述的那样。

2、感觉打开chrome ,开发者工具,发现部分请求URL是404,css和js的



3、找客户要服务器登录的账号,检查nginx配置文件

upstream www.test.com{
 server 127.0.0.1:8080;
}
server {
 listen 80;
 listen 443 ssl http2;
 ssl_certificate /usr/local/nginx/conf/ssl/www.test.com.pem;
 ssl_certificate_key /usr/local/nginx/conf/ssl/www.test.com.key;
 server_name www.test.com;
 access_log /data/wwwlogs/www.test.com_nginx.log combined;
 index index.html index.htm index.jsp;
 root /data/wwwroot/www.test.com;
 
 
 location ~ .*\.(js|css)?$ {
 
 expires 7d;
 access_log off;
 }
?
 location / {
 proxy_pass http://www.test.com;
 include proxy.conf;
 }
}

4、大家有发现上面配置有问题不?刚开始我也没有注意,自认为配置文件是对 的。

打算检查nginx的日志,一遍请求URL,一遍查看nginx果然还是404.(感觉疑惑),明明配置了proxy_pass http://www.test.com。

故障原因:

是因为 “location ~ .*\.(js|css)?$” 这个匹配拦截掉了,请求不能正常发往下一个“location /” ,也就不能正常抵达后端proxy_pass了。

解决方法:

第一种解决方法:是将后端的静态文件(css 和js ),放入前置nginx 机器/data/wwwroot/www.test.com

第二种解决方法 :修改配置文件

upstream www.test.com{
 server 127.0.0.1:8080;
}
server {
 listen 80;
 listen 443 ssl http2;
 ssl_certificate /usr/local/nginx/conf/ssl/www.test.com.pem;
 ssl_certificate_key /usr/local/nginx/conf/ssl/www.test.com.key;
 server_name www.test.com;
 access_log /data/wwwlogs/www.test.com_nginx.log combined;
 index index.html index.htm index.jsp;
 root /data/wwwroot/www.test.com;
 
?
 location ~ .*\.(js|css)?$ {
 proxy_pass http://www.test.com;
 expires 7d;
 access_log off;
 }
?
 location / {
 proxy_pass http://www.test.com;
 include proxy.conf;
 }
}

?

??此账号为华为云开发者社区官方运营账号,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态


本文分享自华为云社区《学习VueRouter,HTML5 History 模式,因为history模式刷新页面会出现404》,作者: DevFeng 。


vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。

如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。

const router=new VueRouter({
  mode: 'history',
  routes: [...]
})

当你使用 history 模式时,URL 就像正常的 url,例如 http://yoursite.com/user/id,也好看!

不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404,这就不好看了。

所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。

#后端配置例子

注意:下列示例假设你在根目录服务这个应用。如果想部署到一个子目录,你需要使用 VueCLI 的

publicPath 选项 (opens new window)和相关的 router base property (opens new window)。你还需要把下列示例中的根目录调整成为子目录 (例如用 RewriteBase /name-of-your-subfolder/ 替换掉 RewriteBase/)。

#Apache

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

除了 mod_rewrite,你也可以使用 FallbackResource (opens new window)。

#nginx

location / {
  try_files $uri $uri/ /index.html;
}

#原生 Node.js

const http=require('http')
const fs=require('fs')
const httpPort=80

http.createServer((req, res)=> {
  fs.readFile('index.html', 'utf-8', (err, content)=> {
    if (err) {
      console.log('We cannot open "index.html" file.')
    }

    res.writeHead(200, {
      'Content-Type': 'text/html; charset=utf-8'
    })

    res.end(content)
  })
}).listen(httpPort, ()=> {
  console.log('Server listening on: http://localhost:%s', httpPort)
})

#基于 Node.js 的 Express

对于Node.js/Express,请考虑使用 connect-history-api-fallback 中间件 (opens new window)。

#Internet InformationServices (IIS)

1. 安装 IIS UrlRewrite(opens new window)

2. 在你的网站根目录中创建一个 web.config 文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Handle History Mode and custom 404/500" stopProcessing="true">
          <match url="(.*)" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

#Caddy

rewrite {
    regexp .*
    to {path} /
}

#Firebase 主机

在你的 firebase.json 中加入:

{
  "hosting": {
    "public": "dist",
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

#警告

给个警告,因为这么做以后,你的服务器就不再返回 404 错误页面,因为对于所有路径都会返回

index.html 文件。为了避免这种情况,你应该在 Vue 应用里面覆盖所有的路由情况,然后再给出一个 404 页面。

const router=new VueRouter({
  mode: 'history',
  routes: [
    { path: '*', component: NotFoundComponent }
  ]
})

或者,如果你使用 Node.js 服务器,你可以用服务端路由匹配到来的 URL,并在没有匹配到路由的时候返回 404,以实现回退。


点击关注,第一时间了解华为云新鲜技术~华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华为云