node学习之路(一)—— 网络请求分分快三计划

作者:分分快三计划
2.querystring.parse()方法回顾

QueryString" 模块用于实现URL参数字符串与参数对象的互相转换
在url.parse()基础上,把参数字符串编程jsonp对象格式:

例子:

分分快三计划 1

模拟登陆

哈哈,写到这里已经很晚了,用node试了试模拟登陆SF,结果404,暂时没有什么思路,等有时间再试试专门开篇讲解咯。这里推荐一篇之前看到的文章:记一次用 NodeJs 实现模拟登录的思路。

一、首先,我们确定一下接口。
/user?act=reg&user=aaa&pass=123456
  {"ok": false, "msg": "原因"}

/user?act=login&user=aaa&pass=123456
  {"ok": true, "msg": "原因"}

querystring.unescape——字符串解码

querystring.unescape('appkey=123&version=1.0.0+')
// 'appkey=123&version=1.0.0 '
二、 文件位置:

分分快三计划 2

node 处理 post 请求实例

当然这里我们可以直接在后台设置响应头进行跨域(CORS),如:

var http = require("http"); // 提供web服务
var query = require("querystring"); // 解析POST请求

http.createServer(function(req,res){
    // 报头添加Access-Control-Allow-Origin标签,值为特定的URL或"*"(表示允许所有域访问当前域)
    res.setHeader("Access-Control-Allow-Origin","*");

    var postdata = '';
    // 一旦监听器被添加,可读流会触发 'data' 事件
    req.addListener("data",function(chunk){
        postdata  = chunk;
    })
    // 'end' 事件表明已经得到了完整的 body
    req.addListener("end",function(){
        console.log(postdata);  // 'appid=xiaoqingnian'
        // 将接收到参数串转换位为json对象
        var params = query.parse(postdata);
        if(params.userid == 'xiaoqingnian'){
            res.end('{"name":"zhaomenghuan","age":"22"}');
        }
    })

}).listen(8080);

我们通过流的形式接收前端post传递的参数,通过监听data和end事件,后面在讲解event模块的时候再深入探究。

CORS默认只支持GET/POST这两种http请求类型,如果要开启PUT/DELETE之类的方式,需要在服务端在添加一个"Access-Control-Allow-Methods"报头标签:

res.setHeader(
    "Access-Control-Allow-Methods",
    "PUT, GET, POST, DELETE, HEAD, PATCH"
);

前端访问代码如下:

var xhr = new XMLHttpRequest();
xhr.onload = function () {
    console.log(this.responseText);
};
xhr.onreadystatechange = function() {
    console.log(this.readyState);
};

xhr.open("post", "http://127.0.0.1:8080", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("userid=xiaoqingnian");

复习一下:

基础模块 作用
fs fs模块用于对系统文件及目录进行读写操作
http 创建服务器。e.g.http.createServer();
queryString 把url带的参数串转化为数组对象
url 直接解析URL中字符串,提炼出我们需要的结果。
提示:
    querystring主要用来解析POST数据(如‘querystring.parse()’)
    Url主要用来解析GET数据(比如‘url.parse()’)。

url.format——格式化URL对象

我们可以通过url.format方法将一个解析后的URL对象格式化成url字符串,用法为:

url.format(urlObj)

例子:

url.format({
  protocol: 'http:',
  slashes: true,
  auth: 'user:pass',
  host: 'host.com:8080',
  port: '8080',
  hostname: 'host.com',
  hash: '#hash',
  search: '?query=string',
  query: 'query=string',
  pathname: '/p/a/t/h',
  path: '/p/a/t/h?query=string',
  href: 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash' 
})

结果为:
'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'
三、服务器接受数据后,处理并返回data的思路
  1. 接口名为user。如果url中地址不指向user,就显示404,否则进入2;
  2. 用户是登录还是注册?
  3. 如果既不是注册也不是登录。就提示“未知action”;
    4.“登录部分”接下去是如果密码正确,就提示“登录成功”,否则提示“密码不正确”;
    如果是注册,检测账号是否存在,也进行相应的提示。
const http = require('http');
const fs = require('fs');
const querystring = require('querystring');
const urlLib = require('url');

var users = {}; //将注册信息保存在缓存中

var server = http.createServer(function (req, res) {
    // 解析数据    
    var str = '';
    req.on("data", function (data) {
        str  = data;
    });
    req.on("end", function () {
        var obj = urlLib.parse(req.url, true);

        var url = obj.pathname;
        const GET = obj.query;
        const POST = querystring.parse(url);

        // 区分接口和文件读取
        if (url == '/user') { //读取‘url’接口下的文件时
            switch (GET.act) {
                case 'reg':
                    //用户名已经存在 
                    if (users[GET.user]) {
                        res.write('{"ok":false, "msg":"已经注册过了!"}');
                    } else {
                        // 插入到users
                        users[GET.user] = GET.pass;
                        res.write('{"ok":true,"msg":"注册成功!"}');
                    }
                    break;
                case 'login':
                    //用户名是否存在
                    if (users[GET.user]) {
                        if (user[GET.pass] === GET.pass) { //密码是否正确
                            res.write('{"ok":true,"msg":"登录成功!"}');
                        } else {
                            res.write('{"ok":flase,"msg":"密码不正确!"}');
                        }
                    } else { //用户名不存在
                        res.write('{"ok":false,"msg":"用户名不存在"}');
                    }
                    break;
                default:
                    res.write('{"ok":false,"msg":"未知操作"}');
            }
            res.end();
        } else { //读取别的文件
            var file_name = './www'   url;
            fs.readFile(file_name, function (err, data) {
                if (data) {
                    res.write(data);
                } else {
                    res.write("404");
                }
                res.end();
            });
        }
    });
});

server.listen(8080);

user.html文件代码:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title></title>
  <!--引入jQuery文件-->
  <script src="ajax.js" charset="utf-8"></script>

  <!--我们需要的js代码-->
  <script type="text/javascript">
    window.onload = function () {
      var oTxtUser = document.getElementById('user');
      var oTxtPass = document.getElementById('pass');
      var oBtnReg = document.getElementById('reg_btn');
      var oBtnLogin = document.getElementById('login_btn');

      oBtnLogin.onclick = function () {
        ajax({
          url: '/user',
          data: {
            act: 'login',
            user: oTxtUser.value,
            pass: oTxtPass.value
          },
          type: 'get',
          success: function (str) {
            var json = eval('('   str   ')');

            if (json.ok) {
              alert('登录成功');
            } else {
              alert('登录失败:'   json.msg);
            }
          },
          error: function () {
            alert('通信错误');
          }
        });
      };

      oBtnReg.onclick = function () {
        ajax({
          url: '/user',
          data: {
            act: 'reg',
            user: oTxtUser.value,
            pass: oTxtPass.value
          },
          type: 'get',
          success: function (str) {
            var json = eval('('   str   ')');

            if (json.ok) {
              alert('注册成功');
            } else {
              alert('注册失败:'   json.msg);
            }
          },
          error: function () {
            alert('通信错误');
          }
        });
      };
    };
  </script>
</head>

<body>
  用户:
  <input type="text" id="user">
  <br> 密码:
  <input type="password" id="pass">
  <br>
  <input type="button" value="注册" id="reg_btn">
  <input type="button" value="登录" id="login_btn">
</body>

</html>

执行以下server.js,然后在浏览器中打开user.html页面。值得注意的是跨域问题,
分分快三计划 3
分分快三计划 4

注意:我们应该在服务器上跑,而不是只打开本地静态页面!

接下来就正常玩耍吧……

url.parse——解析url字符串

上述代码中比较关键的是我们通过url.parse方法将url字符串转成Url对象,用法如下:

url.parse(urlStr, [parseQueryString], [slashesDenoteHost])

接收参数:

  • urlStr:url字符串
  • parseQueryString:参数为true时,query会被解析为JSON格式,否则为普通字符串格式,默认为false;如:
    • 参数为true:query: { userid: 'xiaoqingnian', callback: 'jsonpcallback' }
    • 参数为false:query: 'userid=xiaoqingnian&callback=jsonpcallback'
  • slashesDenoteHost:默认为false,当url是 ‘http://’ 或 ‘ftp://’ 等标志的协议前缀打头的,或直接以地址打头,如 ‘127.0.0.1’ 或 ‘localhost’ 时候是没有区别的;当且仅当以2个斜杠打头的时候,比如 ‘//127.0.0.1’ 才有区别。这时候,如果其值为true,则第一个单个 ‘/’ 之前的部分被解析为 ‘host’ 和 ‘hostname’,如 ” host : ‘127.0.0.1’ “,如果为false,包括2个反斜杠在内的所有字符串被解析为pathname。如:
> url.parse('//www.foo/bar',true,true)
Url {
  protocol: null,
  slashes: true,
  auth: null,
  host: 'www.foo',
  port: null,
  hostname: 'www.foo',
  hash: null,
  search: '',
  query: {},
  pathname: '/bar',
  path: '/bar',
  href: '//www.foo/bar' }
> url.parse('//www.foo/bar',true,false)
Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: '',
  query: {},
  pathname: '//www.foo/bar',
  path: '//www.foo/bar',
  href: '//www.foo/bar' }

这里的URL对象和浏览器中的location对象类似,location中如果我们需要使用类似的方法,我们需要自己构造。

思路:

url.resolve——拼接url字符串

我们可以通过url.resolve为URL或 href 插入 或 替换原有的标签,接收参数:
from源地址,to需要添加或替换的标签。

url.resolve(from, to)

例子为:

url.resolve('/one/two/three', 'four')
=> '/one/two/four'
url.resolve('http://example.com/', '/one')    
=> 'http://example.com/one'
url.resolve('http://example.com/one', '/two') 
=> 'http://example.com/two'
1.url.parse()方法回顾:
 var url = require('url');
 var queryUrl = "http://localhost:8888/bb?name=bigbear&memo=helloworld" 
 console.log(url.parse(queryUrl)) ;

运行结果:

{ 
    protocol: 'http:',
    slashes: true,
    auth: null,
    host: 'localhost:8888',
    port: '8888',
    hostname: 'localhost',
    hash: null,
    search: '?name=bigbear&memo=helloworld',
    query: 'name=bigbear&memo=helloworld',
    pathname: '/bb',
    path: '/bb?name=bigbear&memo=helloworld',
    href: 'http://localhost:8888/bb?name=bigbear&memo=helloworld'
}

说明:

query: 查询字符串中的参数部分(问号后面部分字符串),或者使用 querystring.parse() 解析后返回的对象。

参考

  • nodejs官网API文档
  • 进击Node.js基础(一)
  • Node.js v4.2.4 文档 中文版
  • 文章代码源码下载:http://zhaomenghuan.github.io/resource/blog/demo/20160929.zip

querystring.escape——字符串编码

querystring.escape('appkey=123&version=1.0.0 ')
// 'appkey=123&version=1.0.0+'

querystring.stringify(querystring.encode)——序列化对象

querystring.stringify(obj[, sep][, eq][, options])
querystring.encode(obj[, sep][, eq][, options])

接收参数

  • obj: 欲转换的对象
  • sep:设置分隔符,默认为 ‘&'
  • eq:设置赋值符,默认为 ‘='
querystring.stringify({foo: 'bar', baz: ['qux', 'quux'], corge: ''})
// 'foo=bar&baz=qux&baz=quux&corge='

querystring.stringify({foo: 'bar', baz: ['qux', 'quux'], corge: ''},',',':')
// 'foo:bar,baz:qux,baz:quux,corge:'

http.request(options, callback)

options可以是一个对象或一个字符串。如果options是一个字符串, 它将自动使用url.parse()解析。http.request() 返回一个 http.ClientRequest类的实例。ClientRequest实例是一个可写流对象。如果需要用POST请求上传一个文件的话,就将其写入到ClientRequest对象。使用http.request()方法时都必须总是调用req.end()以表明这个请求已经完成,即使响应body里没有任何数据。如果在请求期间发生错误(DNS解析、TCP级别的错误或实际HTTP解析错误),在返回的请求对象会触发一个'error'事件。

Options配置说明:

  • host:请求发送到的服务器的域名或IP地址。默认为'localhost'。
  • hostname:用于支持url.parse()。hostname比host更好一些
  • port:远程服务器的端口。默认值为80。
  • localAddress:用于绑定网络连接的本地接口。
  • socketPath:Unix域套接字(使用host:port或socketPath)
  • method:指定HTTP请求方法的字符串。默认为'GET'。
  • path:请求路径。默认为'/'。如果有查询字符串,则需要包含。例如'/index.html?page=12'。请求路径包含非法字符时抛出异常。目前,只否决空格,不过在未来可能改变。
  • headers:包含请求头的对象。
  • auth:用于计算认证头的基本认证,即'user:password'
  • agent:控制Agent的行为。当使用了一个Agent的时候,请求将默认为Connection: keep-alive。可能的值为:
    • undefined(默认):在这个主机和端口上使用[全局Agent][]。
    • Agent对象:在Agent中显式使用passed。
    • false:在对Agent进行资源池的时候,选择停用连接,默认请求为:Connection: close。
  • keepAlive:{Boolean} 保持资源池周围的套接字在未来被用于其它请求。默认值为false
  • keepAliveMsecs:{Integer} 当使用HTTP KeepAlive的时候,通过正在保持活动的套接字发送TCP KeepAlive包的频繁程度。默认值为1000。仅当keepAlive被设置为true时才相关。

Query String 模块Query String

爬虫实例

这里我们使用es6的新特性写:

const https = require('https');
https.get('https://segmentfault.com/blogs', (res) => {
    console.log('statusCode: ', res.statusCode);
    console.log('headers: ', res.headers);
    var data = '';
    res.on('data', (chunk) => {
        data  = chunk;
    });
    res.on('end', () => {
        console.log(data);
    })
}).on('error', (e) => {
    console.error(e);
});

这样一小段代码我们就可以拿到segmentfault的博客页面的源码,需要说明的是因为这里请求的网站是https协议,所以我们需要引入https模块,用法同http一致。下面需要做的是解析html代码,下面我们需要做的就是解析源码,这里我们可以引入cheerio,一个node版的类jQuery模块,npm地址:https://www.npmjs.com/package/cheerio。

首先第一步安装:

npm install cheerio

然后就是将html代码load进来,如下:

var cheerio = require('cheerio'),
var $ = cheerio.load(html);

最后我们就是分析dom结构咯,通过类似于jQuery的方法获取DOM元素的内容,然后就将数据重新组装成json结构的数据。这里就是分析源码然后,这里我就不详细分析了,直接上代码:

function htmlparser(html){
    var baseUrl = 'https://segmentfault.com';

    var $ = cheerio.load(html);
    var bloglist = $('.stream-list__item');

    var data = [];

    bloglist.each(function(item){
        var page = $(this);
        var summary = page.find('.summary');
        var blogrank = page.find('.blog-rank');

        var title = summary.find('.title a').text();
        var href = baseUrl   summary.find('.title a').attr('href');
        var author = summary.find('.author li a').first().text().trim();
        var origin = summary.find('.author li a').last().text().trim();
        var time = summary.find('.author li span')[0].nextSibling.data.trim();
        var excerpt = summary.find('p.excerpt').text().trim();
        var votes = blogrank.find('.votes').text().trim();
        var views = blogrank.find('.views').text().trim();

        data.push({
            title: title,
            href: href,
            author: author,
            origin: origin,
            time: time,
            votes: votes,
            views: views,
            excerpt: excerpt
        })
    })

    return data;
}

结果如下:

[{ title: '转换流',
    href: 'https://segmentfault.com/a/1190000007036273',
    author: 'SwiftGG翻译组',
    origin: 'SwiftGG翻译组',
    time: '1 小时前',
    votes: '0推荐',
    views: '14浏览',
    excerpt: '作者:Erica Sadun,原文链接,原文日期:2016-08-29译者:Darren;校对:shank
s;定稿:千叶知风 我在很多地方都表达了我对流的喜爱。我在 Swift Cookbook 中介绍了一些。现
在,我将通过 Pearson 的内容更新计划...' },
......
]

这里我们只是抓取了文章列表的一页,如果需要抓取多页,只需要将内容再次封装一下,传入一个地址参数?page=2,如:https://segmentfault.com/blogs?page=2
另外我们也没有将详情页进一步爬虫,毕竟文章的目的只是学习,同时方便自己查看列表,这里保留原始地址。

温馨提示:大家不要都拿sf做测试哦,不然玩坏了就不好。

node 处理 get 请求实例

毕竟作为一个前端,我们经常需要自己搭建一个服务器做测试,这里我们先来讲一下node http模块作为服务器端使用。首先我们需要,使用createServer创建一个服务,然后通过listen监听客服端http请求。

我们可以创建一个最简单的服务器,在页面输出hello world,我们可以创建helloworld.js,内容如下:

var http = require('http');

http.createServer(function(request, response){
    response.writeHead(200, { 'Content-Type': 'text-plain' });
    response.end('hello world!')
}).listen(8888);

在命令行输入node helloworld.js即可,我们打开在浏览器打开 world!。

下面我们在本地写一个页面,通过jsonp访问我们创建的node服务器:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <div id="output"></div>

        <script type="text/javascript">
            // 创建script标签
            function importScript(src){
                var el = document.createElement('script');
                el.src = src;
                el.async = true;
                el.defer = true;
                document.body.appendChild(el);
            }

            // 响应的方法
            function jsonpcallback(rs) {
                console.log(JSON.stringify(rs));
                document.getElementById("output").innerHTML = JSON.stringify(rs);
            }

            // 发起get请求
            importScript('http://127.0.0.1:8888?userid=xiaoqingnian&callback=jsonpcallback');
        </script>
    </body>
</html>

我们当然需要将上述node服务器中的代码稍作修改:

var http = require('http'); // 提供web服务
var url = require('url');   // 解析GET请求

var data = {
    'name': 'zhaomenghuan', 
    'age': '22'
};

http.createServer(function(req, res){  
    // 将url字符串转换成Url对象
    var params = url.parse(req.url, true);  
    console.log(params);
    // 查询参数
    if(params.query){
        // 根据附件条件查询
        if(params.query.userid === 'xiaoqingnian'){
            // 判断是否为jsonp方式请求,若是则使用jsonp方式,否则为普通web方式
            if (params.query.callback) {  
                var resurlt =  params.query.callback   '('   JSON.stringify(data)   ')';
                res.end(resurlt);  
            } else {  
                res.end(JSON.stringify(data));
            }
        } 
    }      
}).listen(8888);

我们在命令行可以看到:

Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: '?userid=xiaoqingnian&callback=jsonpcallback',
  query: { userid: 'xiaoqingnian', callback: 'jsonpcallback' },
  pathname: '/',
  path: '/?userid=xiaoqingnian&callback=jsonpcallback',
  href: '/?userid=xiaoqingnian&callback=jsonpcallback' }

经过服务器端jsonp处理,然后返回一个函数:

jsonpcallback({"name":"zhaomenghuan","age":"22"})

而我们在页面中定义了一个jsonpcallback()的方法,所以当我们在请求页面动态生成script调用服务器地址,这样相当于在页面执行了下我们定义的函数。jsonp的实现原理主要是script标签src可以跨域执行代码,类似于你引用js库,然后调用这个js库里面的方法;这是这里我们可以认为反过来了,你是在本地定义函数,调用的逻辑通过服务器返回的一个函数执行了,所以jsonp并没有什么神奇的,和XMLHttpRequest、ajax半毛钱关系都没有,而且JSONP需要服务器端支持,始终是无状态连接,不能获悉连接状态和错误事件,而且只能走GET的形式。

http.request与http.get的区别

node http模块创建服务器

前言

一直以来想深入学习一下node,一来是自己目前也没有什么时间去学习服务器端语言,但是有时候又想自己撸一下服务器端,本着爱折腾的精神开始写一写关于node的文章记录学习心得。本系列文章不会过多去讲解node安装、基本API等内容,而是通过一些实例去总结常用用法。本文主要讲解node网络操作的相关内容,node中的网络操作依赖于http模块,http模块提供了两种使用方式:

  • 作为服务器端使用,创建一个http服务器,监听http客户端请求并返回响应;
  • 作为客户端使用,发起一个http客户端请求,获取服务器端响应。

url 模块API详解

node http模块发起请求

平时喜欢看博客,毕竟买书要钱而且有时候没有耐心读完整本书,所以很喜欢逛一些网站,但是很多时候把所有的站逛一下又没有那么多时间,哈哈,所以就准备把常去的网站的文章爬出来做一个文章列表,一来省去收集的时间,二来借此熟悉熟悉node相关的东西。这里我们首先看一个爬虫的小例子,下面以SF为例加以说明(希望不要被封号)。

文章来源:小青年原创
发布时间:2016-09-29
关键词:JavaScript,nodejs,http,url ,Query String,爬虫
转载需标注本文原始地址: http://zhaomenghuan.github.io/#!/blog/20160929

http.get(options, callback)

因为大部分的请求是没有报文体的GET请求,所以Node提供了这种便捷的方法。该方法与http.request()的唯一区别是它设置的是GET方法并自动调用req.end()。

querystring.parse(querystring.decode)——解析query字符串

querystring.parse(str[, sep][, eq][, options])
querystring.decode(str[, sep][, eq][, options])

接收参数

  • str:欲转换的字符串
  • sep:设置分隔符,默认为 ‘&'
  • eq:设置赋值符,默认为 ‘='
  • [options] maxKeys 可接受字符串的最大长度,默认为1000
querystring.parse('foo=bar&baz=qux&baz=quux&corge=')
// { foo: 'bar', baz: [ 'qux', 'quux' ], corge: '' }

querystring.parse('foo:bar,baz:qux,baz:quux,corge:',',',':')
{ foo: 'bar', baz: [ 'qux', 'quux' ], corge: '' }

本文由分分快三计划发布,转载请注明来源

关键词: 分分快三计划 Node node 学习之路