【问题标题】:Error when refreshing the same page twice两次刷新同一页面时出错
【发布时间】:2020-04-12 05:02:01
【问题描述】:

我正在尝试使用 nodejs 和 nginx 在远程服务器上部署 Angular 应用程序。 我构建了应用程序,并使用节点应用程序为它提供服务。 Nginx 在这里充当反向代理。 我可以毫无问题地访问该网站并导航。但是,当我尝试刷新当前页面时,我的浏览器再也找不到它了:响应得到 404。

但如果我在 url 栏中输入域,我可以再次访问该网站。

有谁知道我哪里出错了?

这是节点应用程序和 nginx 的代码和配置:

var express  = require('express');
var app      = express();                               // create our app w/ express
var morgan = require('morgan');             // log requests to the console (express4)
var bodyParser = require('body-parser');    // pull information from HTML POST (express4)
var methodOverride = require('method-override'); // simulate DELETE and PUT (express4)
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const mustacheExpress = require("mustache-express");

dotenv.config();

// configuration =================

mongoose.connect(process.env.DB_CONNECT, { useNewUrlParser: true }, () => {
    console.log("connected to DB !");
  });

app.use(express.static("../front-end/dist/website"));                 
app.use(morgan('dev'));                                         // log every request to the console
app.use(bodyParser.urlencoded({'extended':'true'}));            // parse application/x-www-form-urlencoded
app.use(bodyParser.json());                                     // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());

// Middleware
app.use(express.json());

// Templating
app.engine("html", mustacheExpress());

//import routes
const authRoute = require("./routes/auth");
const devisRoute = require("./routes/devis");
const messageRoute = require("./routes/message");
const actuRoute = require("./routes/actu");

//Routes middlewares
app.use("/api/user", authRoute);

app.use("/api/sendDevis", devisRoute);

app.use("/api/message", messageRoute);

app.use("/api/actu", actuRoute);


// listen (start app with node server.js) ======================================
app.listen(3000);


server {

        root /var/www/domain.com/html;
        index index.html index.htm index.nginx-debian.html;

        server_name domain.com www.domain.com;

        location / {
              proxy_pass http://localhost:3000;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection 'upgrade';
              proxy_set_header Host $host;
              proxy_cache_bypass $http_upgrade;
        }

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; # m                                                         anaged by Certbot
    ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; #                                                          managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot


}
server {
    if ($host = www.domain.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = domain.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


        listen 80;
        listen [::]:80;

        server_name domain.com www.domain.com;
    return 404; # managed by Certbot

}

【问题讨论】:

  • 如果你刷新主页,它总是有效吗?前端导航是使用服务器还是在客户端作为单页应用程序 (SPA) 完成?最后,您在“../front-end/dist/website”中托管了哪些文件。如果没有这些信息,我最好的猜测是您在 SPA 中使用客户端路由,并且没有每个 URL 的文件(如果有的话,很容易解决)。
  • 是的,主页总是可以刷新的。导航是用 Angular 的路由器制作的,所以我认为它是在客户端完成的?我在 dist repo 中托管构建的输出(ng build --prod)。

标签: node.js angular express nginx


【解决方案1】:

在使用单页应用程序进行客户端路由时,这是一个容易落入的陷阱。

诀窍是这样的:当您在浏览器中导航时,浏览器不会向您的服务器发出请求。当您刷新页面时,浏览器确实 将请求发送到服务器。由于您正在制作 SPA,因此有关页面内容的所有信息都在您的 Javascript 中,并且该 Javascript 已加载到您的 index.html 文件中。您的服务器上唯一存在的文件是您的根文件,express.static 中间件将 URL 映射到您的文件,因此没有文件可供它查找(因此是 404)。

您需要在服务器端始终提供您的 index.html 文件无论请求什么 html 文件

最简单的解决方案是使用 Express 的内置 .sendFile() 函数在您的路由中添加一个后备处理程序last。简单、无细微差别的方式是这样的:

// ... ^^ all your other routes
router.get("*",
  // The '*' means match *everything*
  (req,res)=>{
    res.sendFile('index.html'); // Probaby need to set some options here to start in the right directory...
  }
);

您可能想使用不同的中间件或添加自己的花里胡哨的功能来包括压缩等,但想法是一样的。

【讨论】:

  • 问题解决了!顺便说一句,我也忘了使用 path.resolve() 方法。非常感谢!
猜你喜欢
  • 2015-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-03
  • 1970-01-01
  • 2016-04-15
  • 2013-01-25
  • 1970-01-01
相关资源
最近更新 更多