谁有做过或者看过使用Meteor
做的多个APP项目然后将他们通过http-proxy
或者nginx反向代理
整合成一个项目的?
多个Meteor
项目分别用不同端口,例如APP0:3000
、APP1:4000
、APP2:5000
、APP3:6000
。然后让APP0映射到:80/
,APP1
映射到:80/app1
子目录,APP2
映射到:80/app2
子目录,APP3
映射到:80/app3
子目录。
求高手指点!
尝试了很久,用如下方式解决了!
搭建MutilMeteorApps
通过Meteor官网的项目示例,我们可以很快做出我们的Web应用。但是在实际的开发当中,我们往往由多人开发,每个人可能负责开发几个项目,却发布在一个服务器应用中。这种是如何实现的呢?通常我们可以使用服务器的反向代理机制将不同的Web项目映射到同一个端口中,现在我们就来实现搭建一个MutilMeteorApps。
首先,我们创建一个文件夹MutilMeteorApps,里面会有很多单独的MeteorApp。
$ mkdir MutilMeteorApps
$ cd MutilMeteorApps
接着,我们创建一个frame项目,这个项目作为整个MutilMeteorApps的框架项目。
$ meteor create frame
因为frame项目仅仅为集群项目提供框架,我们删除所有默认文件,新建/lib/config.js
文件。
__meteor_runtime_config__.serverId = "myServerId";
然后我们新建一个/client/frame.html
:
<head>
<title>项目主框架</title>
</head>
<body>
<div>
<a href="/app1" target="showFrame">app1</a>
<a href="/app2" target="showFrame">app2</a>
<a href="/app3" target="showFrame">app3</a>
</div>
<div id="main">
<iframe frameborder=0 width="100%" height="800" marginheight=0 marginwidth=0 scrolling=no src="/app1" name="showFrame">
</div>
</body>
接下来我们就来构造我们的三个app项目,这三个项目我们不用自己做,我们就用Meteor官方提供的项目就可以了:
$ meteor create --example leaderboard
$ meteor create --example todos
$ meteor create --example wordplay
Meteor内部就提供了node的一个modules,名字叫http-proxy
,这是一个用node做的http代理模块。我们在MutilMeteorApps文件夹新建如下文件和文件夹:
/MutilMeteorApps
|-- /proxy
|-- proxy.js
|-- node_modules
将http-proxy
模块复制到node_modules
文件夹中,然后修改proxy.js
文件:
var proxy = require('http-proxy');
var options = {
replaceRelativePath:true,
pathnameOnly:true,
router:{
//package和sockjs从框架中找
'/packages':'192.168.30.100:3000/packages',
'/sockjs':'192.168.30.100:3000/sockjs',
//各个项目从不同端口找
'/app1':'192.168.30.100:4000/',
'/app2':'192.168.30.100:5000/',
'/app3':'192.168.30.100:6000/',
//设置根目录
'/':'192.168.30.100:3000/',
}
};
proxy.createServer(options).listen(80);
需要注意的是,host尽量配置为本机ip地址或者域名ip地址。这样,我们就将不同端口的项目代理到同一端口80下了。接着我们运行所有的项目以及proxy.js
这个node
程序:
## 启动frame项目 ##
$ meteor --port 3000
## 启动leaderboard项目 ##
$ meteor --port 4000
## 启动todos项目 ##
$ meteor --port 5000
## 启动wordplay项目 ##
$ meteor --port 6000
## 启动proxy代理 ##
$ node proxy.js
我们可以试一试每个项目单独启动能否成功,答案是显然的,因为端口都没有冲突。然后我们试着访问http://127.0.0.1
,点击这些链接。先不管为什么frame为什么没出来,但是我们发现点出来的项目虽然出来了,但是不停的再刷新。
这是为什么呢?其实我也不知道,但是我发现他刷新的速度和socket刷新的速度是一致的。于是我猜测,可能他认为这是几个不同的项目,所以出现这种不断比较不断刷新的递归现象,时间长了自然会对服务器有影响。还记得我们之前为frame配置的lib目录吗,这是我花了很久才找到的配置方法,中间走了不少弯路。只要将这个目录为你所有的项目中添加,告诉他们之间其实是同一个项目即可。
此时,三个项目都没出现刷新的问题,但是因为没有数据,所以三个显示的都不怎么好看。思考了一下,可能是三个都是连接各自的数据库,因此,我们统一数据库好了,设置环境变量set MONGO_URL=mongodb://192.168.30.100:27017
,再次运行所有项目。
依然没有达到我们都目的,好的,我们再来做大胆的尝试。我觉得是因为不同端口的项目都在尝试连接80端口的项目,而80端口被映射到了3000端口上。因此,我们将所有项目拆解为client/server/public/collections
几个文件夹来试一试。最后,将所有的服务器资源(public、server)统统放到frame项目中去。
最后成功!但是使用nodejs启动有点麻烦,如果Meteor框架frame自己能启动就最好了。很简单,Meteor虽然不能使用nodejs代码,但是能通过全局变量Npm
获取nodejs模块,使用方法为Npm.require()
,之后改动就很简单了吧!
虽然解决了,但是老大并不满意。他需要通过反向代理的方式实现各个app独立分离,减少服务器一次性的开销,我的这个解决方案虽然解决了标(分离和反向代理),但是没解决本(减少服务器开销)。不知道其他人还有没有更好的点子?我现在是已经没辙了!
我来解释一下 @a272121742同学 的解决方案为什么无法满足我的要求。
使用Meteor开发出的web应用程序是单页面应用(SPA),Meteor会将所有客户端逻辑(包括所有模板)全部编译成js,并加载到单个页面上。这对于小程序是没有任何问题的,但是如果开发一个大型的企业级应用,则是致命的。可以想象,打开登录页面就要加载全部程序,也许就有几十兆。客户会急死,浏览器也会崩溃。更进一步,如果开发移动版应用,脆弱的手机浏览器遇到这种巨无霸的单页面应用,恐怕立即就挂掉了。
解决办法之一就是将程序模块化,并且将不同的模块部署到不同的Meteor实例上,后台指向同一个MongoDB即可。前台一个主App框架通过router将不同的模块菜单路由到不同的Meteor实例,每个页面实际只加载单个模块的代码。这不需要做任何特殊开发,只要预先规划好功能模块即可。
但是问题来了:每个Meteor实例需要独占一个端口,如果这个系统需要支持外网访问,意味着需要为每个Meteor实例在防火墙上开放一个端口。如果你的程序有100个模块,你需要对着客户说“网管哥哥帮我在firewall开100个端口好吗?”然后你必定会收获一个白眼。
完美的Meteor模块化开发方案,必须解决每个Meteor实例独占一个端口的问题。
通过HTTP Server的代理和反向代理,可以实现子域名到端口的映射,例如 app1.company.com 可映射到 host.com:8001,app2.company.com 可映射到 host.com:8002,听起来不错,但是依然不能解决问题。首先这种代理对Meteor会失效,因为Meteor的数据推送是通过WebSocket机制,在页面初始化时,每个页面会启动一个WebSocket并绑定到指定端口。上述例子中 app1.company.com和app2.company.com两个页面都会试图和company.com:80端口建立WebSocket连接。除非HTTP代理支持WebSocket,否则此路不通。第二个问题是,为了支持100个模块,你得注册100个二级域名,你会不会觉得很烦?
最终的方案,还是需要回答 @a272121742同学 开头提出的:
启动n个Meteor App,例如 Server:3000、Server:4000、Server:5000 通过某种机制,使得对 Server:3000的访问映射到 Server:80/,Server:4000的访问映射到 Server:80/app1、Server:5000的访问映射到 Server:80/app2… 这样就实现了单个端口,单个域名或IP地址,指向不同的Meteor应用程序(模块)
目前尚无答案,也许需要研究一下HTTP代理,听说Nginx已经支持Websocket代理,有人熟悉吗?