windows 怎么部署node

windows 怎么部署node,第1张

准备工作在 Windows 中用 Node.js 进行开发一度是非常麻烦的事,但是现在这一状况相较于一两年前有了较大改善。这也是为什么,在选择 Windows 7 还是 Windows 10 作为本文主题之时,我们犹豫不决的原因。尽管 Windows 7 仍旧非常流行,而且 Windows 10 有一些不好的风闻(由于评价标准及数据收集范围的不同),我们还是决定选择 Windows 10 为试验对象,因为确保最新的操作系统对保证应用安全至关重要。在本文中,我们将尽可能使用最新的工具与应用(并使用其64位版本)。笔者知道在公司环境中这可能无法保证,但保持工具的前卫是很重要的。本文所有的安装都会在本机中进行。我不建议在 Cygwin 中搭建 Node 环境。此外,尽管 VirtualBox 是免费的,当我在 Windows 机器上运行 Linux 虚拟机时,却总是问题不断。步骤1:安装 Git首先,安装 Git。使用默认设置,这些设置是相当合理的。笔者通常会在主目录下创建一个项目文件夹。设置时,右键单击该文件夹,选择 “Git bash here”,再通过 git --version 指令检查 git 版本。这是很好的 bash 环境,你可以创建一个 .bash_profile ,在你打开 bash 窗口时执行。此外,这不是 cmd.exe 窗口,你可以查看一些选项(单击左上角的图标)。你可以通过鼠标中键将文本拷贝至窗口(就像在创建的 Linux 终端一样)。步骤2:在 Windows 10 上安装 Node.js下载并 安装 Node.js 。使用其 LTS(长期支持)版本。笔者不建议并排安装多个版本,因为 Node 版本管理器并未正式支持 Windows ——不过,你仍有一些备选方案,比如 nvm-windows 或 nodist 。其实,即便是在其他系统中,全局安装不同版本的 node 工具仍然像是在自找麻烦。步骤3:更新 npmnpm 伴随着 Node 而来。成功安装 Node.js 之后,包管理器 npm 也应当可用了。打开一个 bash shell,通过 npm --version 检查版本号。如果 npm 是 2.x 版本,则应该升级到版本3,这能解决许多问题(对我们而言,最重要的是其处理对等依赖的方式)。在开始菜单中搜索 Power Shell,以管理员身份运行,并遵循 以下步骤 。步骤4:安装Visual Studio 与PythonNode 包通常会依赖带有本地代码的包,因此你必须安装 Visual Studio。Node-gpy 是围绕 Python GYP (Generate Your Projects)的一款包装程序,该工具能为 Gcc, XCode 以及 Visual Studio 生成项目文件。由于 Windows 开发实际上是通过 Visual Studio 进行的,我们会用其支持 Visual Studio。安装 Python(2.x 版本)如你所见,你会用到 Python,因此 下载其64位的 2.x 版本 并安装之。你可以遵循默认设置,并选择 “Add to path (添加至路径)”选项。这会将 Python 二进制添加到全局路径,意味着最终你要先登出再登陆。下一步,进入环境变量设置(在系统,高级设置中),并将GYP_MSVS_VERSION=2015 添加到全局变量中,因为下一步是 Visual Studio 2015 的安装。安装 Visual Studio (VS2015)不同于2012之前的版本,VS2015 能与64位的 Node.js 和谐工作。很快,我们将学习 Node-gyp 针对 Windows 10 的教程 。除非你的机器上已经安装了完整的 VS,请下载 Visual Studio 2015 社区版 ,选择自定义安装并选定完全的 Visual C++ 分支(不带 XP 支持),此外,在工具中选择Windows SDKs。如果在安装过程中出现任何差错,你可以点击程序与特性(Programs and Features),选择 VS2015,进行更改与修正。在 gyp 的安装手册中还提到了 Windows 7 SDKs,但是我们在前面已经安装了 Win 8 SDKs,所以希望不会用到 Win 7 SDKs。步骤5:安装包依赖目前,笔者正在开发 Trace 中的告警微服务,所以我会通过 npm -i 指令安装所需的包依赖。得到的结果如下图所示:Fsevents 是可选依赖,且只能用于 OSX 系统;这只是一个警告——其余模块并无问题。该微服务用到了 Postgres 与RabbitMQ,因此笔者也安装了二者(连同 Erlang)。此处,与 OSX brew(与 apt、Chocolatey 相似的一款包管理器)以及 rocket(一款服务管理器)配置相比,唯一的不同是我必须 手动在 15672 端口启用 web 管理员 。在数据库端,笔者添加了默认用户,并创建了一个数据库。不过,这些都可以在 PgAdmin 客户端轻松完成。步骤6:处理环境变量通常,Node.js 项目都高度依赖环境变量。从上面的项目截图中可以看到,IS_INTERACTIVE 是一个环境变量(env var),这在 Linux 与 OSX 系统中很容易定义,但是在 Windows 中则有一点不同。在 package.json 的脚本部分,你可以使用安装在本地的 node 模块。笔者建议你尽量避免通过 npm -g 指令全局地安装包。此外,笔者也不建议在 Windows (更精确地说,在跨平台项目中)的脚本部分直接添加环境变量,其实,我们有别的选择。Npm 会直接将这些指令 传递至 OS ,在本例中,传递到 NT 命令解释器(cmd.exe)。此处,最快捷的解决办法是将脚本行拷贝到我们的 bash 窗口,并运行之。但是,理所当然,这不是长远的解决办法。最新发布的 Windows bash shell 支持 (目前仍处于测试阶段)很可能会解决此问题。最清楚的解决方法是对每一脚本行使用一条指令(如你所见,我们的 npm run lint 指令运行良好)。任何依赖于 flashvars (临时环境变量)或试图同时完成许多操作的指令,都应该写在某个 /scripts 文件夹下,作为 Node 可执行的JavaScript 文件。不要使用 bash 脚本,cmd 无法处理这些脚本。Cmd.ex 支持 &&,因此两三条指令还行,将一整个 shell 脚本写做一行就不行了(尤其不应带有 bash 语言特性)。为了支持脚本,这是可行的。但是为了运行我们的应用,就需要许多环境变量。在 RisingStack,我们在开发阶段会使用 nodemon (不过,有些人或许会用 pm2)。Nodemon 是一款文件监视器,会在开始时根据你定义的环境变量,解析 nodemon.json 文件。笔者通常会在 .gitignore_global 文件(在主目录下,记得用 git config --global core.excludesfile ~/.gitignore_global 进行初始化)中加入nodemon.* ,这样一来,我的项目中便可以有多个 nodemon json 模板。尽管不是非常优雅的解决方案,笔者通常会全局地安装 nodemon。有时,在开发中直接手动启动 nodemon,而不是通过适当的运行脚本,更为简单。有了上面的 json,现在可以启动我的微服务了,如下所示:当然,由于笔者不愿监视文件变化,nodemon 可能不是最佳的仅用于运行脚本的解决方案。对于那些情况,笔者通常会将 nodemon.json 文件转化为 nodemon.sh,将每一个环境变量导出至后者。请注意:你可以根据自己的喜好随意命名该文件,但是不要忘记将其添加至忽略文件 ——不慎将该文件推入资源库会造成很大的麻烦:export NODE_ENV="development" export PORT=3060 export AMQP_URI="amqp://localhost:5672/" export EMAIL_SENDER_NAME="Developer" #etc.之后,笔者可以在命令行中以其为源文件(源引nodemon.dev.sh)——这样做是为了我们当前使用的 MinGW bash,但是,如果将其转化为传统的 bat 文件,会更为简单。由于我们的数据库设置需要几个环境变量,而笔者不愿监视之,这是最快也最粗暴的在本地运行的方法。在云供应商环境中,笔者会更加合理地设置环境变量。到此为止,项目顺利运行了,就如同在 OSX 或 Linux 系统中一样。以上即为我们简短的在 Windows 10 中配置 Node.js 的教程。npm 中的一些模块可能不支持 Windows,但是这一情况正在好转。Windows 拥有许多美观友好的 GUI 工具,Visual Studio 也是很强大的武器。如果你的团队愿意承担额外的开销,这或许是一个可行的选择。OneAPM 能帮助您轻松锁定Node.js 应用性能瓶颈,通过强大的Trace 记录逐层分析,直至锁定行级问题代码。以用户角度展示系统响应速度,以地域和浏览器维度统计用户使用情况。

第一步,用node输出一个hello world

    var http=require('http') 

    http.createServer(function(req,res){ 

        var urlPares=url.parse(req.url) 

        var query=querystring.parse(urlPares.query) 

        res.end('hello world') 

    }).listen(80)

大部分的node教程在这里会告诉你,我们很容易的建立的一个服务器。但是在实际使我们通常使用的是express.(f**k,难道Node必须要用express吗?自己实现一个Web应用框架真的很难吗?)其实并不是。

那么既然打算自己写我们首先要知道我们要做哪些事情。 1.路由或者智能路由 2.静态文件输出 3.session/cookie 4.模版渲染 5.数据库处理 6.文件上传

第二步,路由

路由好高大上的名字,它是干啥的?url对应具体方法就是它该做的事情。 那么我们为什么不让url对应xxx文件的xx方法。 例如:/user/login能不能自动对应到user.js的login方法上。实现起来很难么?其实只需要几句代码

   

 var fs = require("fs") 

    module.exports=function(req,res){ 

        var query=req.query 

        var urlPares=req.urlPares 

        var pathname=urlPares.pathname 

        var arr=pathname.split("/") 

        req.arr=arr 

        //start 这段代码处理默认行为。可以先忽略 

        if(arr.length==0||arr.length==1){ 

            arr=["","index","index"] 

        }else if(arr.length==2){ 

            arr.push("index") 

        } 

        if(arr[1]==""){ 

            arr[1]="index" 

        } 

        if(arr[2]==""){ 

            arr[2]="index" 

        } 

        //end 这段代码处理默认行为。可以先忽略 

        if (fs.existsSync(APP_PATH+'/controller/'+arr[1]+'.js')){ 

            var controller=require('./controller/'+arr[1]) 

            if(controller[arr[2]]){ 

                controller[arr[2]](req,res) 

            }else{ 

                res.writeHead(404,{'Content-Type': 'text/plain' }) 

                res.end("你访问的控制器不存在指定方法") 

            } 

        }else{ 

            res.writeHead(404,{'Content-Type': 'text/plain' }) 

            res.end("你访问的路径不存在") 

        } 

    }

通过fs判断文件是否存在。然后去require它就行了。APP_PATH是个全局变量表示程序入口的路径。

第三步,静态文件输出

静态文件输出我们需要一个库MIME

  

  var url = require("url") 

    var fs = require("fs") 

    var mime = require('mime') 

    /** 

     * [[检测是否为静态资源]] 

     * @param   {Object}   req [[Description]] 

     * @param   {[[Type]]} res [[Description]] 

     * @returns {bool} [[Description]] 

     */ 

    module.exports = function (req, res) { 

        //正则表达式检测文件后缀 

        var url_resource_reg = /.*\.(html|htm|gif|jpg|jpeg|bmp|webp|htc|swf|png|ico|txt|js|css)/ 

        if (!url_resource_reg.test(req.url)) { 

            return false 

        } 

        var urlPares = url.parse(req.url) 

        var pathname = urlPares.pathname 

        var fileUrl = APP_PATH + "/static" + pathname 

        if (fs.existsSync(fileUrl)) { 

            var contentType = mime.lookup(fileUrl) 

            res.setHeader('Content-Type', contentType || "text/plain") 

            var fileStream = fs.createReadStream(fileUrl) 

            fileStream.pipe(res) 

            fileStream.on('end', function () { 

                res.end() 

            }) 

            return true 

        } else { 

            return false 

        } 

    } 

第四步,session/cookie

这里稍微有点。但是代码量也不多

    var sessions = {} 

    var sessionKey = 'session_key' 

    var EXPIRES = 30 * 60 * 1000 

    function randString(size) { 

        var result = '' 

        var allChar = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' 

        size = size || 1 

        while (size--) { 

            result += allChar.charAt(rand(0, allChar.length - 1)) 

        } 

        return result 

    } 

    var generate = function () { 

        var session = {} 

        session.id = Date.now() + randString(12) 

        session.cookies = { 

            expire: Date.now() + EXPIRES 

        } 

        sessions[session.id] = session 

        return session 

    } 

    var parseCookie= function (cookie) { 

        var cookies = {} 

        if (!cookie) { 

            return cookies 

        } 

        var list = cookie.split("") 

        for (var i = 0 i < list.length i++) { 

            var pair = list[i].split("=") 

            cookies[pair[0].trim()] = pair[1] 

        } 

        return cookies 

    } 

    var serializeCookies = function (cookies) { 

        var arr = [] 

        for (var key in cookies) { 

            arr.push(serialize(key, cookies[key])) 

        } 

        return arr 

    } 

    var serialize = function (name, value, option) { 

        var pairs = [name + '=' + encodeURI(value)] 

        //设置cookie默认共用"/"路径 

        option = option || { 

            path: "/" 

        } 

        if (option.maxAge) pairs.push('Max-Age=' + option.maxAge) 

        if (option.domain) pairs.push('Domain=' + option.domain) 

        if (option.path) pairs.push('Path=' + option.path) 

        if (option.expires) pairs.push('Expires=' + option.expires) 

        if (option.httpOnly) pairs.push('HttpOnly') 

        if (option.secure) pairs.push('Secure') 

        return pairs.join(' ') 

    } 

    module.exports = function (req, res) { 

        req.cookies = parseCookie(req.headers.cookie) 

        var id = req.cookies[sessionKey] 

        if (!id) { 

            req.session = generate() 

        } else { 

            var session = sessions[id] 

            if (session) { 

                if (session.cookies.expire > Date.now()) { 

                    session.cookies.expire = Date.now() + EXPIRES 

                    req.session = session 

                } else { 

                    delete sessions[id] 

                    req.session = generate() 

                } 

            } else { 

                req.session = generate() 

            } 

        } 

        for (var key in sessions) { 

            if (sessions[key].cookies.expire < Date.now()) { 

                delete sessions[key] 

            } 

        } 

        var writeHead = res.writeHead 

        res.writeHead = function () { 

            delete req.cookies[ham_sessionKey] 

            var sessionStr = serialize(ham_sessionKey, req.session.id) 

            res.setHeader('Set-Cookie', serializeCookies(req.cookies).concat(sessionStr)) 

            return writeHead.apply(res, arguments) 

        } 

    }

第五步,模版渲染

这是最简单的。

第六步,数据库处理

这里可以是用一些ORM框架。

第七步,文件上传,post

第八步,就是你把上面的代码组织起来。


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/436142.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-28
下一篇2023-05-28

发表评论

登录后才能评论

评论列表(0条)

    保存