Egg: 反向代理之后的静态文件路径问题

Created on 26 Feb 2017  ·  27Comments  ·  Source: eggjs/egg

在生产环境部署时,我们经常使用 nginx 反向代理我们的 nodejs 程序,如下:

location /uc/{  
  rewrite /uc/(.*) /$1 break;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_set_header X-NginX-Proxy true;
  proxy_http_version 1.1;
  proxy_pass http://172.16.0.10:7001/;
  proxy_redirect off;
} 

经测试,使用这种 rewrite /uc/(.*) /$1 break; 是可以解决 eggrouter 的问题

但是无法解决静态资源引用的问题。 请教 EGG 中如何解决?

express 的解决方案如下:

node + express app.js

// 静态文件目录
var staticDir = path.join(__dirname, 'public');
app.enable('trust proxy');
app.use('/public', express.static(staticDir)); 

views/login.html

<link rel="stylesheet" href="public/libs/bootstrap/css/bootstrap.min.css">

以上注意静态资源引用没有使用 /public/ 而是使用的 public/

Most helpful comment

可以先看看 express 这块的源码下。

发自我的 iPhone

在 2017年2月27日,22:54,天马行空 notifications@github.com 写道:

实例验证, 如果不使用 trust proxy ,则代理失败。


You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.

All 27 comments

自己解决了,EGG 中不需要 app.enable('trust proxy'); 只需要注意静态资源引用不能使用 /public/ 而是使用的 public/ 即可。

这个问题依然存在, 原先是由于 niginx 缓存存在的原因, 以为正常了.

这个与 trust proxy 没有关系,试试调整一下 static 的参数: https://github.com/eggjs/egg-static#configuration

没有上下文环境的, 使用是没有问题的, 静态文件 以 /public/ 引用, 但使用了 nginx 反向代理后, 如加入前缀 /uc 后, 静态文件的访问自然就有问题, 这方面 express 是通过 app.enable('trust proxy'); 解决了这个问题, 难道 你们在生产环境部署时都没有感到过这样的问题? 也许你们的静态文件是走 cdn 的, 自然也不会有这样的问题.

如果是在 nginx 后面,你可以调整 static 的 prefix 参数来适应一下?

例如你将 prefix 改成 /uc/public,express 的 trust proxy 可以帮你自动判断出来前缀是 uc ?

那 静态资源引用是否也要加上 prefix ?

express 的 trust proxy 是跟 koa 的 proxy 类似的东西吧? 我印象中只是用来配置是否解析来源 ip 的, 跟 static 的 prefix 应该没啥关系才对

@hsxiaoma 如果路径会不一样,你在静态资源引用里面也要使用相对路径

我的意思可能你还没有明白,举个列子吧

本地开发

// {app-root}/app/router.js
app.get('/','...');
app.get('/info','...');
app.get('/info/:id','...');
<!-- {app-root}/app/view/index.html -->
<script src="/public/mui/js/mui.min.js"></script>

<!-- {app-root}/app/view/info/index.html -->
<script src="/public/mui/js/mui.min.js"></script>

以上列子在没有上下文的情况下,一切正常。

远程服务器环境

经过 nginx 反向代理后加入了 /uc/

其地址映射则发生了变化

/               -->  /uc/
/info         -->  /uc/info
/info/:id    --> /uc/info/:id

/public/...  -->  /uc/public/...

路由的问题已经解决, 但静态文件没办法解决, 使用 相对路径也是不行的。

express 经测试, 已经解决了这个问题。详细参见: 见下楼层有详细描述

那你最终想访问 /uc/public 还是直接访问 /public 呢,如果你不想变模板的话应该是 /public?

@hsxiaoma 你在模板中使用相对路径引用静态资源,例如你的页面路径在本地为 /page/index.htm,想引用一个 /public/js/index.js,那你的路径就写 ../public/js/index.js,这样当你的所有的路径都加了一个 /uc 前缀,页面变成了 /uc/page/index.js,静态文件变成了 /uc/public/js/index.js,他们的相对路径还是不变的,通过 ../public/js/index.js 还是能引用到。

很不幸, 其实有很多时候 , 路由的地址和你实际的 html的位置是不一致的。
如:
/uc/info --> app/view/info/index.html
../public/.. --> ../../public/...
如果按路由地址来,显然是不合理的, 因为路由属于极易改变的东西

如果你能确定你的前端 nginx 配置的前缀是多少,判断在 nginx 后面时给静态资源加上这个前缀就可以了。

// app/extend/helper.js
module.exports = {
  getStatic(path) {
    if (this.ctx.get('X-NginX-Proxy')) return `/uc${path}`;
    return path;
  }
}

// view/index.html
<link rel="stylesheet" href="{{ helper.getStatic(/public/libs/bootstrap/css/bootstrap.min.css)}}">

你的那篇文章放到一个可以被其他人访问的地方吧。

@hsxiaoma 你是 UC 哪个部门的? UC 这边不都走构建静态资源绝对路径的方式么?这属于工程化的范畴了,之前云龙有专门阐述过这块的,都是推荐用绝对路径的。

补充文档

生产环境下 nginx 反向代理多个 node + express 应用时静态资源路径的问题

现有以下 node + express 程序:

nodejs-app1:  http://127.0.0.1:3000
nodejs-app2:  http://127.0.0.1:3001 

nginx 的映射为:

http://yourdoamin/app1  -->  http://127.0.0.1:3000
http://yourdoamin/app2  -->  http://127.0.0.1:3001

使用 express 时静态文件设置都是以 / 为开头的,此时由于 nginx 映射的地址有 app1 或者 app2 前缀,导致原有的 /public/ 静态文件的地址失效,如何解决这个问题呢?

app.js 中使用:

参考: 代理之后的 Express

app.enable(‘trust proxy’);

在所有的视图或引用静态文件的地方,一律使用 public/...

部分代码示例:

nginx.conf

upstream app1 {
    server   127.0.0.1:3000;
}
upstream app2 {
    server   127.0.0.1:3001;
}

server { 

    location /app1/{ 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_max_temp_file_size 0;
        proxy_pass http://app1/;
        proxy_redirect off;
        proxy_read_timeout 240s;
    } 

    location /app2/{ 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_max_temp_file_size 0;
        proxy_pass http://app2/;
        proxy_redirect off;
        proxy_read_timeout 240s;
    }  

} 

node + express

// app.js
// 静态文件目录
var staticDir = path.join(__dirname, 'public');
app.enable('trust proxy');
app.use('/public', express.static(staticDir)); 

views/login.html

<link rel="stylesheet" href="public/libs/bootstrap/css/bootstrap.min.css">

以上注意静态资源引用没有使用 /public/ 而是使用的 public/

以上静态资源在不同的应用会自动加上反向代理的路径:
如:
app1 下的 实际会转换为 app1/public/libs/bootstrap/css/bootstrap.min.css
app2 下的 实际会转换为 app2/public/libs/bootstrap/css/bootstrap.min.css

@dead-horse 你不觉得你的解决方案很纠结吗?

你这个解法不就是用相对路径来屏蔽掉了前面的 app1 / app2 前缀么?与 trust proxy 到底有什么关系?

<link rel="stylesheet" href="public/libs/bootstrap/css/bootstrap.min.css">

sorry,我并没没有深究其中原因。 但实例验证, 如果不使用 trust proxy ,则代理失败。

首先,你得先弄明白trust proxy是干嘛用的

是的, 也许我的引用是有问题的, 但我还需要去验证一下。 但这个问题如果使用 CDN 后就不复存在了。

向 @dead-horse @fengmk2 大牛学习

可以先看看 express 这块的源码下。

发自我的 iPhone

在 2017年2月27日,22:54,天马行空 notifications@github.com 写道:

实例验证, 如果不使用 trust proxy ,则代理失败。


You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.

设置 trust proxy 为非假值会带来两个重要变化:
反向代理可能设置 X-Forwarded-Proto 来告诉应用使用 https 或简单的 http 协议。请参考 req.protocol。
req.ip 和 req.ips 的值将会由 X-Forwarded-For 中列出的 IP 地址构成。

trust proxy 只会影响如何获取客户端的真实 ip 和协议,所以与你这里提到的问题没有关系,真正解决静态资源路径问题的是你用了相对路径来引用静态资源:

你在模板中使用相对路径引用静态资源,例如你的页面路径在本地为 /page/index.htm,想引用一个 /public/js/index.js,那你的路径就写 ../public/js/index.js,这样当你的所有的路径都加了一个 /uc 前缀,页面变成了 /uc/page/index.js,静态文件变成了 /uc/public/js/index.js,他们的相对路径还是不变的,通过 ../public/js/index.js 还是能引用到。

你好!请问这问题最后怎么处理呢?我也遇到了同样问题,在模板中写成相对路径也解决不了。

我现在也遇到了这个问题,通过ip可以访问,但是通过nginx代理后就提示找不到js了

Was this page helpful?
0 / 5 - 0 ratings