运行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 相关文章推荐
用jscript实现列出安装的软件列表
Jun 18 Javascript
十分钟打造AutoComplete自动完成效果代码
Dec 26 Javascript
AJAX的跨域与JSONP(为文章自动添加短址的功能)
Jan 17 Javascript
如何让页面在打开时自动刷新一次让图片全部显示
Dec 17 Javascript
window.open的页面如何刷新(父页面)上层页面
Dec 28 Javascript
js闭包的用途详解
Nov 09 Javascript
JavaScript实现搜索框的自动完成功能(一)
Feb 25 Javascript
JSON字符串和JSON对象相互转化实例详解
Jan 05 Javascript
JavaScript实现的斑马线表格效果【隔行变色】
Sep 18 Javascript
Vue实现导出excel表格功能
Mar 30 Javascript
js实现类似iphone的网页滑屏解锁功能示例【附源码下载】
Jun 10 Javascript
解决微信浏览器缓存站点入口文件(IIS部署Vue项目)
Jun 17 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
我常用的几个类
2006/10/09 PHP
JS 网站性能优化笔记
2011/05/24 PHP
ThinkPHP3.1.3版本新特性概述
2014/06/19 PHP
浅谈php(codeigniter)安全性注意事项
2017/04/06 PHP
使两个iframe的高度与内容自适应,且相等
2006/11/20 Javascript
从新浪弄下来的全屏广告代码 与使用说明
2007/03/15 Javascript
JS读取cookies信息(记录用户名)
2012/01/10 Javascript
javascript版的in_array函数(判断数组中是否存在特定值)
2014/05/09 Javascript
javascript中的altKey 和 Event属性大全
2015/11/06 Javascript
jQuery+ajax实现文章点赞功能的方法
2015/12/31 Javascript
jQuery实现点击查看大图并以弹框的形式居中
2016/08/08 Javascript
Nodejs中Express 常用中间件 body-parser 实现解析
2017/05/22 NodeJs
使用Vue自定义指令实现Select组件
2018/05/24 Javascript
Vue2.0 实现移动端图片上传功能
2018/05/30 Javascript
mpvue项目中使用第三方UI组件库的方法
2018/09/30 Javascript
vue如何在用户要关闭当前网页时弹出提示的实现
2020/05/31 Javascript
ES5和ES6中类的区别总结
2020/12/21 Javascript
如何封装Vue Element的table表格组件
2021/02/06 Vue.js
Python 自动刷博客浏览量实例代码
2017/06/14 Python
Python数据分析之双色球中蓝红球分析统计示例
2018/02/03 Python
使用Python制作新型冠状病毒实时疫情图
2020/01/28 Python
记一次pyinstaller打包pygame项目为exe的过程(带图片)
2020/03/02 Python
Python标准库shutil模块使用方法解析
2020/03/10 Python
Python实现从N个数中找到最大的K个数
2020/04/02 Python
StubHub智利:购买和出售您的门票
2016/11/23 全球购物
数控技术与应用毕业生自荐信
2013/09/24 职场文书
服务中心夜班服务员岗位职责
2013/11/27 职场文书
促销活动计划书
2014/05/02 职场文书
施工安全汇报材料
2014/08/17 职场文书
2014年中学生检讨书大全
2014/10/09 职场文书
2014年大学生工作总结
2014/11/20 职场文书
离职感谢信
2015/01/21 职场文书
母亲节寄语大全
2015/02/27 职场文书
2015医德医风个人工作总结
2015/04/02 职场文书
全家福照片寄语怎么写?
2019/04/02 职场文书
MySQL 用 limit 为什么会影响性能
2021/09/15 MySQL