65.9K
CodeProject 正在变化。 阅读更多。
Home

了解 JavaScript... 在服务器端使用 Node.js

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.64/5 (8投票s)

2012 年 3 月 5 日

CPOL

6分钟阅读

viewsIcon

48055

Node.js 详细介绍

Node.js 简介

Node.js 首先是一个(出人意料地)在服务器端执行的 Google 的 V8 JavaScript 引擎。据说 V8 引擎也用于 Chrome 浏览器。Node.js 可以与 VB 运行时启用 VBScript 相比较。

因此,这使得 JavaScript 可以在服务器端使用。

所有浏览器都有一个 JavaScript 引擎,似乎没有人想到将其开发成服务器端引擎,从而允许 JavaScript 爱好者在服务器端进行编码。现在 Node.js 很受欢迎,微软甚至在其 Azure 云系统中支持 Node.js 脚本(这有助于吸引 JavaScript 开发者使用 Azure)。

本文旨在快速深入探讨一些使用 Node.js 的示例。

Hello World

在文本文件中输入以下行,最好命名为 helloworld.js

console.log('Hello world!'); 

并在命令行中使用 node 引擎运行它

node  c:\work\helloworld.js

要做到以上几点… 先决条件是您已 安装了 Node.js (这类似于安装桌面应用程序。)

Node.js 可以用于什么?

从本质上讲,JavaScript 在 AJAX 方面表现出色,Node.js 的用途似乎也最受欢迎… 发起请求或响应请求。虽然也可以用于其他用途,但您找到的大多数示例都是关于发起或响应服务器请求的。

我们将创建一些示例。

Web 请求示例

以下代码保存在名为 test.js 的文件中,并用 node 执行,它将发出 HTTP 请求以获取页面并打印结果… HTML。

var http = require('http');

var options = {
  host: 'www.google.co.in',
  port: 80,
  path: '',
  method: 'GET'
};

var req = http.request(options, function(res) {
  console.log('STATUS: ' + res.statusCode);
  console.log('HEADERS: ' + JSON.stringify(res.headers));
  res.setEncoding('utf8');
  res.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
  });
});

req.on('error', function(e) {
  console.log('problem with request: ' + e.message);
});

req.write('data\n'); //this line prints first, while the request and the content 
                     //printing happens a bit slow as its an internet call.

req.end();  

脚本的风格与 JavaScript 使用变量、对象和命名空间进行编码 相同。是的… 这以及类似 jQuery 库的使用经验,是本文读者的先决条件。

Node.js 具有内置接口,公开对 HTTP 功能、JSON 等的支持,我们已经使用了上述内容。关于上述 HTTP 请求示例的一些其他细节

http.request - 发起请求,其第二个参数是 JavaScript 回调处理程序风格的回调事件处理程序。

JSON.stringify - 是的,JSON 已内置到 node 引擎中。

事件处理程序如下连接

res.on('data', callback fn); 

在此,响应对象在发出 http 请求后每次接收到数据时都会触发 data 事件。

Node.js 外部库 & npm

除了内置接口,Node.js 还可以使用 nodersshtmlparser 等库。这些库可以使用 npm 安装。

npm - 是 node 的包管理器(我猜它可能在内部使用开源的 rpm -Redhat Linux 包管理器,所以名字是这个,但这只是猜测。如果我猜对了,请告知我。)

已安装的库将位于您的 node 安装目录或用户目录的“node_modules”文件夹中。例如,在 Windows 机器上,“documents and settings”下,例如 c:\Documents and Settings\username\Application Data\npm\node_modules

每天都有许多新的 node 兼容库添加到 github 上… 因此 Node.js 的功能每天都在改进,甚至每小时都在改进… 因此您不必一定要等待 Node.js 发布新版本来编写更好的代码。之所以这样说,另一个原因是,由于它是基于 JavaScript 的,而脚本语言是公共标准… 引擎本身可能不需要/不需要改进,除非 JavaScript 版本升级。

(又一个猜测… 我认为 node 的库是用 JavaScript 编写的… 从我在 node_modules 文件夹中看到的内容推测。我猜对了吗?那么每个好的 JavaScript 开发人员都应该能够为 node 创建库?请告知我。)

使用 xml2js 库解析 RSS Feed

下一个示例使用 node 内置的 HTTP 和文件系统函数支持,以及一个外部库 xml2js,您需要使用 npm 安装它。

一些先决条件… 安装 npm 模块

在命令提示符中输入以下命令来安装 xml2js

npm install xml2js

npm install --global xml2js

解决“找不到 xml2js”错误

我个人在使用 xml2js 时没有成功,除非我将 xml2js 包复制到我的 .js 项目文件夹的根目录中。

解析 RSS Feed 的代码

var http = require('http'),
  fs = require('fs'),
  xml2js = require('xml2js');

////////// code to get xml from url
var options = {
  host: 'www.codeproject.com',
  port: 80,
  path: '/WebServices/ArticleRSS.aspx',
  method: 'GET'
};
var req = http.request(options, function(res) {
  console.log('STATUS: ' + res.statusCode);
  console.log('HEADERS: ' + JSON.stringify(res.headers));
  res.setEncoding('utf8');
  
  var fullResponse = "";
  
  res.on('data', function (chunk) {
    //console.log('BODY: ' + chunk);
    fullResponse = fullResponse+chunk;
  });
  
  res.on('end', function(){
    parser.parseString(chunk);
    console.log(item.title + '\n');
  });
});
req.on('error', function(e) {
  console.log('problem with request: ' + e.message);
});

/////////xml load example from xml from file
fs.readFile(__dirname + '/ArticleRSS.aspx.xml', function(err, data) {
    parser.parseString(data);
    
    jsonObj.channel.item.forEach(function(item){
      console.log(item.title + '\n');
    });                            
    
    console.log('Done');               
    
    process.exit(0);
});

//code to parse xml
var jsonstring = "";
var jsonObj;
var parser = new xml2js.Parser();
parser.addListener('end', function(result) {
    jsonstring = JSON.stringify(result);
    jsonObj = JSON.parse(jsonstring);
    
    console.log('Done');
});

关于上述代码

xml2js 的用法 在此 处进行了解释。

上面的代码获取 CodeProject 文章 RSS Feed 的内容,调用一个处理程序来解析 XML,以提取或打印 RSS 中所有节点的标题。

  • 展示了 forEach 的一个用法示例
  • 展示了使用 process.exit(0) 强制停止 node 程序的示例
  • 展示了从文件系统文件和 Web URL 加载 RSS Feed 的示例。

我可以在 Node.js 中将 jQuery Core 用作外部库吗?

技术上是的。您可以尝试安装 npm 并开始使用它。

npm install jquery

我未能成功,因为某些依赖项对我来说失败了… 仍在排查中。

创建一个完全用 JavaScript 编写的 Web 服务

这是一个服务,它接受搜索字符串,搜索 codeproject.com 并将结果作为 RSS Feed 返回。

可以使用 Node.js 编写完整的服务器端应用程序、服务层等。npm 存储库上提供的一些 SOAP + XML 外部库允许您这样做。

为了现在保持简单(因为为此示例创建合适的 WSDL 服务似乎需要更多的代码和测试),我用一个服务器快速构建了一个 REST 服务… 全部用 JavaScript 完成。请记住,不需要 Web 服务器、套接字编程等。

在下面的示例中,我们正在创建并托管一个处理 REST 服务请求的 Web 服务器。

使用四个外部库

  • qs - 允许轻松获取和解析我们服务器请求的 querystring
  • htmlparser - 允许解析返回的 HTML
  • soupselect - 允许遍历 CodeProject 搜索结果页面 HTML 输出中的一组 HTML 元素
  • rss - 允许生成 RSS Feed

当然,还有内置的 HTTP 方法。我所有的代码都使用回调处理程序编写的… 所以方法不返回任何东西,因此没有一行代码必须等待才能使用返回的值。尽管这种编码风格使得代码的可读性有些复杂,但它允许保持 Node.js 的优势 – 非阻塞操作。是的,JavaScript 开发者将实现并行性,而无需编写任何套接字或为实现异步执行执行任何特殊操作。

代码

var http = require('http'),
rss = require('rss'),
qs=require('querystring'),
htmlparser = require("htmlparser"),
htmlselect = require('soupselect');

/////////// Create and start the server to handle requests
http.createServer(function (request, response) {
  if (request.url.indexOf('searchcp')==-1)
  {  
    response.writeHead(200, {'Content-Type': 'text/html'});
    response.end('Invalid call\n');
  }
  else
  {  
    //tell the client that return value is of rss type
    response.writeHead(200, {'Content-Type': 'application/rss+xml'});
    
    //extract the searchquery from the querystring.. this is a REST service
    var str_querystring = request.url.substring(request.url.indexOf('searchcp'));
    var searchString = qs.parse(str_querystring).searchcp;
    console.log('\nsearch string:'+qs.parse(str_querystring).searchcp);
    
    //method call to process the search and print rss
    processquery(searchString, response);
  }
}).listen(8080);
console.log('Server running at https://:8080/');
function processquery(searchString, responseObj)
{ 
  
// code to get xml
var options = {
  host: 'www.codeproject.com',
  port: 80,
  path: '/search.aspx?q='+encodeURIComponent(searchString)+'&sbo=kw',
  method: 'POST'
};
var handler = new htmlparser.DefaultHandler(function (error, dom) {
    if (error)
    {}
    else
    {    
      var cpsearchresults=[];
      //get nodes in HTML that we are interested in
      //and loop through each node.. each being one search result item
      //of codeproject search result HTML.. 
      //**depends on codeproject HTML not having changed 
      //**since this time when I tested.
          
      htmlselect.select(dom, "div.result").forEach(function (ele){
        tmpTitle = htmlselect.select(ele, "span.title a");
        if (tmpTitle != undefined){
          if (tmpTitle[0] != undefined) {
              
            var itemTitle=""; itemURL="";    
            try{
              itemTitle = tmpTitle[0].children[0].data;
              itemURL = tmpTitle[0].attribs.href;
                                                   
              if (itemTitle != "" && itemURL != "")
              {
                tmpObj = {Title:itemTitle, URL:itemURL};              
                cpsearchresults.push(tmpObj);
                
                //print(cpsearchresults[cpsearchresults.length-1].Title);
              }
            }
            catch(err)
            {
              //print('Err:'+err);
               //skip record and continue
            }    
        }}
      });       
      
      ///////////// Generate RSS feed
      var feed = new rss({
          title: 'Codeproject search result Sample RSS Feed',
          description: 'Code project search Results RSS feed through node.js sample',
          feed_url: 'http://codeproject.com',
          site_url: 'http://codeproject.com',
          author: 'You'
      });  
          
      /* loop over data and add to feed    */
      cpsearchresults.forEach(function(item){
        //print(item.Title);
        feed.item({
            title:  item.Title,
            url: 'https://codeproject.org.cn'+item.URL          
        });                             
      
      });
                    
      //Print the RSS feed out as response
      responseObj.write(feed.xml());            
      responseObj.end();                    
    }
});
var html_parser = new htmlparser.Parser(handler);

var req = http.request(options, function(res) {
  console.log('STATUS: ' + res.statusCode);
  //console.log('HEADERS: ' + JSON.stringify(res.headers));
  res.setEncoding('utf8');
  
  var alldata = "";
  res.on('data', function (chunk) {
    alldata = alldata+chunk;
  });
  res.on('end', function(){
    html_parser.parseComplete(alldata);
  });  
});

req.on('error', function(e) {
  console.log('problem with request: ' + e.message);
});

req.write('data\n');
req.end();
}

function print(value)
{
  console.log('\n'+value);
}

上面的示例与之前的示例类似,直到获取内容的那一步… 上一个示例获取的是 RSS,这个示例获取的是 HTML 页面。

然后使用 soupselect 库(在此处记录) 提取 + 遍历 CodeProject 搜索结果页面的 HTML 中的搜索结果节点

然后创建一个包含搜索结果标题 + 链接的数组。

然后使用 Node.js rss 库 将该数组转换为 RSS Feed,并以 HTML 响应的形式打印出来。

Node 的核心目标 - 非阻塞操作

Node.js 执行第一行代码,然后执行第二行… 甚至不等第一行完成,如果第一行调用了一个需要一段时间才能完成的方法。

我不确定是否有可能强制 node 在某一行上等待… 如果在实现的某个时刻,您甚至需要这样做。(有可能吗?谁知道?请告知我。)

暂时就到这里。感谢阅读!

© . All rights reserved.