运行Node.js的IIS扩展iisnode安装配置笔记


Posted in Javascript onMarch 02, 2015

今年年初打算用Node.js基于Express框架重写博客程序,从此告别ASP.NET。然而,我目前用的VPS是Windows Server系统、IIS服务器,如果让Express和IIS都监听80端口,明显会产生冲突。幸好,有一个叫做iisnode的扩展可以把Node.js程序托管到IIS。而且,这样托管之后也意味着可以使用IIS里面的各种功能(进程管理、GZip压缩、日志、缓存、权限控制、域名绑定等)。

要使用iisnode,得安装:

1.Node.js
2.IIS的URL Rewrite模块
3.iisnode

装好之后,还是按照常规操作,在IIS管理器中创建站点,指向Express程序的目录,关键是还要增加一个web.config文件:

<configuration>

    <system.webServer>

        <handlers>

            <add name="iisnode" path="bin/www" verb="*" modules="iisnode" resourceType="Unspecified" requireAccess="Script" />

        </handlers>
        <rewrite>

            <rules>

                <rule name="all">

                    <match url="/*" />

                    <action type="Rewrite" url="bin/www" />

                </rule>

            </rules>

        </rewrite>

    </system.webServer>

</configuration>

这段内容也可以通过IIS管理器的可视化界面配置。大概意思把所有请求重写到bin/www,而且使用iisnode扩展运行bin/www。然而,打开站点后,却出现了这样的错误提示:

请求筛选模块被配置为拒绝包含 hiddenSegment 节的 URL 中的路径

起初是觉得不明所以,后来突然醒悟,ASP.NET里面的bin目录是个不允许访问的特殊目录。把请求重写到bin/www,恰好命中了这条规则。所以呢,改一下目录名就好了,比如把bin改成launch(事实证明这不是好做法,后面再说),web.config也要对应调整:
<configuration>

    <system.webServer>

        <handlers>

            <add name="iisnode" path="launch/www" verb="*" modules="iisnode" resourceType="Unspecified" requireAccess="Script" />

        </handlers>
        <rewrite>

            <rules>

                <rule name="all">

                    <match url="/*" />

                    <action type="Rewrite" url="launch/www" />

                </rule>

            </rules>

        </rewrite>

    </system.webServer>

</configuration>

在IIS管理器中重启站点后再次访问,终于运行起来了,不容易啊!不过还是高兴得太早了。

在测试程序功能的过程中,竟然发现获取到的IP为空。在Express框架中,IP是通过req.ip获取的,而req.ip又是从请求头的REMOTE_ADDR获取值。通过一段简单的测试代码,发现REMOTE_ADDR的值也为空。很明显,从IIS到Node.js的过程中,这段头信息丢失了。Google一番之后,发现iisnode确有此问题,官方提供的解决方案是使用X-Forword-For,不过我又发现了另外一个办法。

Web.config中有一段配置(加到</system.webServer>前)可以保留REMOTE_ADDR:

<iisnode promoteServerVars="REMOTE_ADDR" />

根据说明,保留的REMOTE_ADDR会被改名为x-iisnode-REMOTE_ADDR,所以还得把req.ip的值覆盖一次,在Express的app.js中增加一个中间件函数:

app.use(function(req, res, next) {

    req.ip = req.headers['x-iisnode-REMOTE_ADDR'];

    next();

});

然而,这样调整后,获取到的IP还是空,这不免让人怀疑,req.ip的赋值是不是失败了。看一下Express的源代码可以发现,req.ip是通过define getter的方式定义的,所以要覆盖它就得再define一次:
app.use(function(req, res, next) {

    Object.defineProperty(req, 'ip', {

        get: function() { return this.headers['x-iisnode-REMOTE_ADDR']; }

    });

    next();

});

这样问题终于解决了,但这不是一个好方法,要是以后Express把req.ip设成只读就麻烦了。

继续测试,又发现另外一个问题。正常来说,博客后台的文件上传功能会把文件传到public/upload这个目录下,但实际上却在launch目录(即原来的bin目录)下生成了public/upload文件夹。其实原因是作为程序入口的www文件是在launch目录下,所以launch目录成了应用程序的执行目录。我的解决办法是,把launch目录的名字改回bin,在根目录下创建一个launch.js去调用bin/www:

#!/usr/bin/env node
require('./bin/www');

然后把程序入口改为launch.js:

<configuration>

    <system.webServer>

        <handlers>

            <add name="iisnode" path="launch.js" verb="*" modules="iisnode" resourceType="Unspecified" requireAccess="Script" />

        </handlers>
        <rewrite>

            <rules>

                <rule name="all">

                    <match url="/*" />

                    <action type="Rewrite" url="launch.js" />

                </rule>

            </rules>

        </rewrite>
        <iisnode promoteServerVars="REMOTE_ADDR" />

    </system.webServer>

</configuration>

显然,iisnode还不是一个成熟的产品,当然Node.js也不是(至今还没1.0),一切都有待进一步探索和完善。

Javascript 相关文章推荐
添加JavaScript重载函数的辅助方法2
Jul 04 Javascript
JavaScript常用脚本汇总(二)
Mar 04 Javascript
简单介绍JavaScript的变量和数据类型
Jun 03 Javascript
原生JS实现网络彩票投注效果
Sep 25 Javascript
js实现表单提交后不重新刷新当前页面
Nov 30 Javascript
浅谈DOM的操作以及性能优化问题-重绘重排
Jan 08 Javascript
JavaScript正则表达式函数总结(常用)
Feb 22 Javascript
vuex actions传递多参数的处理方法
Sep 18 Javascript
PWA介绍及快速上手搭建一个PWA应用的方法
Jan 27 Javascript
JQuery实现ul中添加LI和删除指定的Li元素功能完整示例
Oct 16 jQuery
js实现表单项的全选、反选及删除操作示例
Jun 05 Javascript
JS如何调用WebAssembly编译出来的.wasm文件
Nov 05 Javascript
Javascript动画的实现原理浅析
Mar 02 #Javascript
JavaScript页面模板库handlebars的简单用法
Mar 02 #Javascript
EasyUI中实现form表单提交的示例分享
Mar 01 #Javascript
EasyUI实现二级页面的内容勾选的方法
Mar 01 #Javascript
EasyUI实现第二层弹出框的方法
Mar 01 #Javascript
EasyUI,点击开启编辑框,并且编辑框获得焦点的方法
Mar 01 #Javascript
浅谈EasyUI中Treegrid节点的删除
Mar 01 #Javascript
You might like
Linux下PHP安装mcrypt扩展模块笔记
2014/09/10 PHP
ThinkPHP公共配置文件与各自项目中配置文件组合的方法
2014/11/24 PHP
CI框架封装的常用图像处理方法(缩略图,水印,旋转,上传等)
2016/11/22 PHP
PHP实现微信申请退款功能
2018/10/01 PHP
PHP PDOStatement::closeCursor讲解
2019/01/30 PHP
thinkphp整合系列之极验滑动验证码geetest功能
2019/06/18 PHP
PHP中类与对象功能、用法实例解读
2020/03/27 PHP
克隆javascript对象的三个方法小结
2011/01/12 Javascript
中国地区三级联动下拉菜单效果分析
2012/11/15 Javascript
js报$ is not a function 的问题的解决方法
2014/01/20 Javascript
JS常用表单验证方法总结
2014/05/22 Javascript
微信开发 微信授权详解
2016/10/21 Javascript
Bootstrap表单制作代码
2017/03/17 Javascript
elementUI 设置input的只读或禁用的方法
2018/10/30 Javascript
Mint UI实现A-Z字母排序的城市选择列表
2018/12/28 Javascript
详解在Node.js中发起HTTP请求的5种方法
2019/01/10 Javascript
vue2.0自定义指令示例代码详解
2019/04/25 Javascript
node.js的http.createServer过程深入解析
2019/06/06 Javascript
JS操作字符串转数字的常见方法示例
2019/10/29 Javascript
Node.js文本文件BOM头的去除方法
2020/11/22 Javascript
Python实现合并字典的方法
2015/07/07 Python
在Django的模板中使用认证数据的方法
2015/07/23 Python
python实现简单爬虫功能的示例
2016/10/24 Python
python psutil库安装教程
2018/03/19 Python
Python 通配符删除文件的实例
2018/04/24 Python
python 统计一个列表当中的每一个元素出现了多少次的方法
2018/11/14 Python
完美解决Python matplotlib绘图时汉字显示不正常的问题
2019/01/29 Python
python3 自动识别usb连接状态,即对usb重连的判断方法
2019/07/03 Python
Final类有什么特点
2012/04/25 面试题
会计专业毕业生自荐书
2014/06/25 职场文书
财政局党的群众路线教育实践活动整改方案
2014/09/21 职场文书
局领导领导班子四风对照检查材料
2014/09/27 职场文书
学生违纪检讨书200字
2014/10/21 职场文书
2016年春季运动会加油稿
2015/07/22 职场文书
Python自动化测试PO模型封装过程详解
2021/06/22 Python
详细介绍Java中的CyclicBarrier
2022/04/13 Java/Android