【问题标题】:Express + Nginx. Can't serve static files快递+ Nginx。无法提供静态文件
【发布时间】:2018-03-23 08:55:47
【问题描述】:

这是我的项目文件夹

/
  public/
    index.html
    main.js
    adaptor.js
    main.css
  node_modules/
    socket.io/
  index.js

这是我 index.js 中的静态文件配置

app.use(express.static(path.join(__dirname, '/public')));
app.use(express.static(path.join(__dirname, '/node_modules')));
app.get('/', (req, res)=>{
    res.sendFile(path.join(__dirname, 'public', '/index.html'));
})

这是我的 index.html

  <script src="/socket.io/socket.io.js" charset="utf-8"></script>
  <script src="/adapter.js" charset="utf-8"></script>
  <script src="/main.js" charset="utf-8"></script>

这是我的 nginx 配置

    location / {
            # First attempt to serve request as file, then
            # as directory, then fall back to displaying a 404.
            try_files $uri $uri/ /index.html =404;
            proxy_pass http://localhost:8080;
    }

但我在所有脚本上都得到 404。另一个奇怪的事情是这些文件上的 mime-type 设置为text/HTML

我在这里做错了什么?

我有一个项目,具有相同的项目结构,并且具有相同的配置,但它适用于它,但在这种情况下它不起作用。

【问题讨论】:

  • 是的 __dirname 是 /home/ubuntu 和 nginx root 设置为 /home/ubuntu
  • 你能用 /public/myfile 访问静态文件吗?此外,Nginx 不需要尝试提供 index.html —— 你的节点应用程序正在处理这个问题。
  • 当我记得你正在传递代理时,我删除了关于 Nginx root 的评论——Nginx 根本不应该尝试提供任何文件。您可以从配置中删除try_files 和root。
  • 区分问题出在 Express 还是 nginx 会很有用。如果直接向 Express 服务器发出请求,是否可以访问脚本文件?

标签: node.js express nginx


【解决方案1】:

在/ 前添加. 表示相对路径:

<script src="./socket.io/socket.io.js" charset="utf-8"></script>
<script src="./adapter.js" charset="utf-8"></script>
<script src="./main.js" charset="utf-8"></script>

【讨论】:

  • 我已经尝试过了,但我不认为它应该是这样工作的,因为静态路径设置为 __dirname/public 所以 ./ 不适合它。
  • 您可以发布浏览器请求的完整请求网址吗?
【解决方案2】:

如果你有这个结构:

myApp
  app.js
  -public/
     -js/

在app.js 你应该这样做:

self.app.use(express.static(path.join(__dirname, 'public')));
staticRoutes.forEach(route=> {
            self.app.use(BASEPATH+route,express.static(path.join(__dirname, 'public')));
        });

staticRoutes 是一个类似数组的地方

staticRoutes=[
'services/'
'about/'
];

在html中(开发)

<script type="text/javascript" src="js/util.js"></script>
<a href="/about">About Us</a>

而在生产中使用完整路径 + 协议更安全。

【讨论】:

    【解决方案3】:
    app.use(express.static(path.join(__dirname, '/public')));
    app.use(express.static(path.join(__dirname, '/node_modules')));
    

    我认为这两行是它引发错误的原因。 你可以删除第二个并试一试吗?也许您的 express 应用设置了主要的静态服务文件夹“node_modules”,这就是该应用无法为您的主脚本文件提供服务的原因。

    另外,我不认为将 node_modules 目录作为静态文件夹提供服务是个好主意。我认为在您的设置中,“bower”似乎更适合作为 javascript 包管理器。

    谢谢

    【讨论】:

    • 我很确定express docs 说这没问题。将按顺序搜索第一个静态目录以查找文件。关于为 node_modules 使用包管理器的要点。
    • +1 建议不使用服务器 node_modules。这是一个巨大的目录,可以暴露数以万计的文件。最好只在“公共”文件夹中的某个位置包含您只需要的前端库。
    【解决方案4】:

    您不需要配置 Nginx 和 Express 来提供静态文件。两者都能够独立完成工作,但您可以选择。

    对于这些示例,我假设您的问题中提供了相同的文件结构。

    在这两种配置中,从 HTML 中的 / 加载文件:

    <script src="/main.js"></script> <!-- loads from myapp/public/main.js -->
    

    Express 为静态文件服务器,Nginx 为反向代理

    快递应用

    const express = require('express');
    const app = express();
    
    app.use(express.static('public')); // notice the absence of `__dirname`, explained later on
    
    // if the request URL doesn't match anything in the 'public' folder,
    // it will start searching here next.
    app.use(express.static('some_other_folder'));
    
    // from my testing, express will automatically locate index.html if
    // it is in a static folder. Declaring a route is not required.
    
    /* 
    app.get('/', (req, res) => {
      res.sendFile(path.join(__dirname, 'public', 'index.html'));
    });
    */
    
    app.listen(8080);
    
    // GET / => index.html
    // GET /main.js => main.js
    

    快速旁注:不需要在express.static() 中使用__dirname。在底层(实际上是第 65 行的 here),Express 使用原生 Node.js path.resolve()。来自文档:

    path.resolve() 方法将一系列路径或路径段解析为绝对路径。

    使用path.resolve(__dirname, 'public') 实际上返回与path.resolve('public') 相同的。我认为您的问题实际上是告诉 Nginx 提供静态文件并将相同的请求代理到 Express。好的,继续我的回答。

    Nginx 配置

    server {
      listen 8081; # must be different port from Express
      server_name example.com;
      location / {
        # hand ALL requests back to express
        proxy_pass http://localhost:8080; 
      }
    }
    

    Nginx 作为静态文件服务器,Express 作为 API 服务器

    Nginx 配置

    server {
      listen 8081;
      server_name example.com;
      location / {
        root /path/to/website/public;
        index index.html;
        try_files $uri $uri/ @express; # instead of 404, proxy back to express using a named location block;
        # source: https://stackoverflow.com/a/15467555/8436941
      }
      location @express {
        proxy_pass http://localhost:8080;
      }
    }
    

    快递应用

    const express = require('express');
    const app = express();
    
    // actually, Nginx has already taken care of static files. You can still define other routes for API functions for example.
    app.get('/my/api', (req, res) => {/* query database, etc. */});
    
    app.listen(8080);
    

    希望这会有所帮助!

    【讨论】:

    • 嘿,谢谢,这行得通。我使用了第一个配置。您能否指出我的文档或其他内容,因为我想了解我做错了什么?比如,不使用__dirname 是如何影响解决方案的?同样的配置适用于我的个人项目,以及我为我工作的公司所做的许多项目。
    • 稍后再谈,我认为您最初的问题是 Nginx 是从 /home/ubuntu 提供服务,而不是从公共目录提供服务。当被要求输入main.js 时,它会返回一个 404 并停在那里,从不向 Express 代理任何东西。至于您的其他项目,我无法确定,但我想知道它们是否有效,因为您的 index.html 文件使用src="/public/main.js" 加载了资产。无论如何,很高兴它有效:)
    • 这是有史以来最伟大的答案!在过去的 24 小时里,我几乎被困住了,几乎没有睡 3 小时。然后我找到了这个答案。谢谢@ContinuousLoad。我的所有路线都无法访问,只有主页 / 可以访问。现在,一切正常。谢谢。
    • @bozzmob 谢谢,我很谦虚。听到旷日持久的问题得到解决让我很开心。肯定去过那里。另外,我听说过马川在this answer 中的try_files 中使用命名块的提示。如果您(或任何人)支持我的,请也支持该答案。
    • @ContinuousLoad 3 到 4 年后,这个答案仍在挽救生命。我认为我在其他任何地方都没有看到过关于他们如何握手的清晰解释。泰!
    【解决方案5】:

    从 nginx 配置文件中删除 try_files 指令为我解决了这个问题。

    【讨论】:

    • 这解决了我尝试过的所有解决方案。谢谢,伙计。
    • 这也是我的问题。非常感谢
    猜你喜欢
    • 2022-11-10
    • 2017-04-30
    • 1970-01-01
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 2018-05-18
    相关资源
    最近更新 更多