HTTP实战(nodejs)

目录:
在这里插入图片描述

HTTP(get)

方法 http.get(url[, options][, callback])

  • 参数:
    url < string> | < URL>
    options < Object> ,接受与 http.request() 相同的 options,且 method 始终设置为 GET。从原型继承的属性将被忽略。
    callback < Function>
  • 这个方法与 http.request() 的唯一区别是它将方法设置为 GET 并自动调用 req.end()。
  • callback 调用时只有一个参数,该参数是 http.IncomingMessage 的实例。
    IncomingMessage 对象由 http.Server 或 http.ClientRequest 创建,并分别作为第一个参数传给 ‘request’ 和 ‘response’ 事件。 它可用于访问响应状态、消息头、以及数据。
const http=require('http');

//之前自己新建的jobslist.json,用json-server开启数据模拟服务,会生成这么一个地址
let str='http://localhost:3333/jobslist';

// 或着自己添加参数,生成完整路径
// const url=require('url');//先引入url内置模块
// var params={
//     protocol:'http',
//     host:'localhost:3333',
//     pathname:'/jobslist'
// }
// let str=url.format(params);//这样str="http://localhost:3333/jobslist"

http.get(str,(response)=>{ //由于大多数请求都是没有主体的 GET 请求,因此 Node.js 提供了这个便捷的方法。
    // console.log(response);//看下面截图
    let {statusCode}=response;//解构
    // console.log("statusCode:"+statusCode);//statusCode:200
    var error;
    // statusCode状态码,在浏览器的显示看下面截图
    if(statusCode!=200){
        error=new Error('数据异常');
    }

    // 验证返回的数据  内容的编码,决定浏览器用什么的形式,来读取这个文件
    let contentType=response.headers["content-type"];//浏览器里面是Content-Type,这俩不算一样
    // console.log("contentType:"+contentType);//contentType:application/json; charset=utf-8
    // console.log("查看contentType内容是否正确:"+/application\/json/.test(contentType));//查看contentType内容是否正确:true
    if(!/application\/json/.test(contentType)){
        error=new Error('数据内容不正确');
    }
    if(error){
        console.log(error.message);//把存在error里的信息打印出来,用Error的message属性
        response.resume();//释放内存  消费响应数据来释放内存。
        return;
    }

    // 如果没有异常,那就是能够正常执行
    var rawdata='';
    var num=0;
    // 数据搜集
    response.on('data',function(chunk){
        // data事件  管道流方式
        // 数据流返回的是数据块  多次响应
        // data 如果数据大  会多次执行  持续的过程
        rawdata+=chunk;
        // console.log(chunk);
    })
    // 数据完成
    response.on('end',function(){
    //    做解析
        // 考虑代码的健壮性 加上异常处理,避免程序直接崩掉
        try{
            // console.log(JSON.parse(rawdata));//将一个 JSON 字符串转换为对象
        }catch (err){
            console.log(err);
        }
    })
// error事件    
}).on('error',function(err){
    console.log(err,err.message);
})

console.log(response),response是callback 调用时的参数(http.IncomingMessage 的实例),然后把statusCode解构拿出来了 let {statusCode}=response;
在这里插入图片描述 在这里插入图片描述
F12或ctrl+shift+i,点Network—>all,能够查看状态码、文本类型等信息
在这里插入图片描述
console.log(chunk) 多个数据块接收拼接,最终形成完整的数据
在这里插入图片描述

http常用 statusCode 状态码:
1**:通知   100~200   
2**:成功   200~300    200成功       288 端口号被占用
3**:重定向  300~400   302移动       304缓存
4**:客户端错误         404资源不存在
5**:服务器错误

拉钩代理例子(request)

通过nodejs的http模块实现简单的代理功能。

比如说我们打开拉勾网的网站,现在我们想要自己本地设置一个端口打开,那么怎么去做这个代理呢?
拉勾网原网址:https://m.lagou.com/listmore.json?pageNo=2&pageSize=15
现在我们用这个网址打开:http://localhost:8099/listmore.json?pageNo=2&pageSize=15

1、先用原网址打开:把这串数据的url拿过来,直接地址栏输入,就能得到这串数据。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2、然后现在我们尝试用本地端口打开。

const https=require('https');
const http=require('http');

const baseUrl="https://m.lagou.com";

http.createServer((req,res)=>{
    let url=req.url;
    console.log("req.url:",req.url);//用户请求路径,如果不写默认为 "/"
    res.setHeader('Content-Type','application/json;charset:utf-8;');// 如果乱码 字符集有问题 content-type出了问题 那就重设一下
    res.setHeader('Access-Control-Allow-Origin','*');// 允许跨域,不过一般不设置为*,一般设置为例如 *.baidu.com,baidu.com是一级域名,*是二级域名
    https.get(baseUrl+url,function(res1){
        var rowdata='';
        res1.on('data',function(chunk){ // data 数据流事件
            rowdata+=chunk;//做数据的拼接
        })
        res1.on('end',function(){
            res.write(rowdata);
            res.end();
        })
    })
}).listen(8099,function(){
    // 8099 端口号
    console.log('lcoalhost 8099 start');
})

开启服务:
在这里插入图片描述
如果不写具体的请求参数,那么,request.url会默认为 “/”(服务端控制台查看)
在这里插入图片描述 在这里插入图片描述
现在完整路径打开,能够看到现在 req.url: /listmore.json?pageNo=2&pageSize=15;
另外,显示的这串数据其实就是服务端响应的数据res.write(rowdata)
在这里插入图片描述 在这里插入图片描述

小知识点:一级域名、二级域名
比如百度 m.baidu.com 、 fe.baidu.com, 如果配置 * .baidu.com 那么前面两个网址就能跨域访问。
baidu.com 一级域名(顶级域名) m fe * 这些位置的都是二级域名

大师兄:Noodjs 代理的实现:手动封装代理与http-proxy-middleware插件实现代理

拉钩代理例子(http-proxy-middleware)

安装:

  • npm init -y 先生成package.json文件
  • yarn add http-proxy-middleware@0.21.0 注意不要安装过新的版本,可能不稳定

现在我想配置一个代理,通过匹配 “/fetch” 来走这个代理,
http://localhost:8099/fetch/listmore.json?pageNo=2&pageSize=15 ,同样能访问原站点访问的数据;
原站点:https://m.lagou.com/listmore.json?pageNo=2&pageSize=15

const https = require('https');
const http = require('http');
const proxy = require('http-proxy-middleware');//使用第三方模块 http-proxy-middleware完成代理

http.createServer((req, res) => {
    //console.log(req.url);// "/fetch/listmore.json?pageNo=2&pageSize=15"
  if (/\/fetch/.test(req.url)) {//正则匹配url;如果请求中有"/fetch",就走这个代理
    var params = {
      target: 'https://m.lagou.com',//需要代理服务的站点url
      changeOrigin: true,//基于名称的虚拟托管网站的选项, 设置为true, 本地就会虚拟一个服务器接收你的请求并代你发送该请求,
      pathRewrite: {
        '^/fetch': ''//在真实的请求中,不加"/fetch",所以替换成空""
      }
    }
    var demoProxy = proxy(params);//返回一个高级函数
    return demoProxy(req, res);//把服务的req和res传进代理模块,响应代理结果给客户端
  } else {
    res.write('hello world')
    res.end();
  }
}).listen(8099, function () {
  console.log('localhost 8099 start ...')
}) 

能够看到用代理的站点也能访问。
在这里插入图片描述
在这里插入图片描述

http.request 请求发送、接收

中文文档

  • 两种形式:
    http.request(options[, callback])
    http.request(url[, options][, callback])
  • 参数:
    url < string> | < URL>
    options < Object>
    callback < Function>

(注意注意:咱们下来的两个例子,客户端与服务端都得开着,分两个终端来开启。)

一、post

client.js 客户端

const http=require('http');
const qs=require('querystring');

// 客户端向服务端发送数据

// 假如有这么一个用户信息
var user={name:'sky',age:20}

// 比如发送数据  到  server url://http://localhost:3000
var app=http.request({
    protocol:'http:',
    hostname:'localhost',
    port:3000,
    method:'post'
},(res)=>{
    // 接收响应数据
    var rawdata='';
    res.on('data',(chunk)=>{
        rawdata+=chunk;
    })
    res.on('end',(chunk)=>{
        console.log(rawdata);//服务端响应的数据
    })
})
// 数据发送,先转化成JSON字符串再发送
app.write(qs.stringify(user));
app.end();

server.js 服务端

const http=require('http');

// 接收数据

var serverApp=http.createServer((request,response)=>{
    var rawdata='';//预备拼接数据
    // 接收请求数据,订阅事件
    request.on('data',(chunk)=>{
        rawdata+=chunk;
    })
    request.on('end',()=>{
        console.log(rawdata);//打印接收的全部数据
        response.write('user ok');//回发响应消息
        response.end();
    })
});

serverApp.listen(3000,(err)=>{
    if(!err){
        console.log("端口3000 服务启动正常");
    }
})

服务正常开启,服务端打印接收到的数据,响应结果给客户端:
在这里插入图片描述
客户端收到服务器的响应:
在这里插入图片描述

二、get

通俗来讲,与post最大的不同是url直接携带请求参数。

client.js 客户端

const http = require('http')
const qs = require('querystring');

var user = { name: 'skyget', age: 18 }

//server url:http://localhost:3000
var app = http.request({
    protocol: 'http:',
    hostname: 'localhost',
    port: 3000,
    path: '/user?' + qs.stringify(user),//直接携带参数
    method: 'GET'
}, (res) => {
    // 接收服务端的响应数据
    var rawdata = '';
    res.on('data', (chunk) => {
        rawdata += chunk;
    })
    res.on('end', (chunk) => {
        console.log(rawdata);
    })
})
app.end();

server.js 服务端

const http = require('http');
const url = require('url');

// 接收数据

var serverApp = http.createServer((request, response) => {
    let strUrl = request.url;//请求url
    console.log(request.url);
    let query = url.parse(strUrl, true).query;//解析参数,?后面的
    console.log(query.name, query.age)
    response.write('ok:' + query.name);
    response.end();
})

serverApp.listen(3000, (err) => {
    if (!err) {
        console.log('localhost 3000 start...')
    }
})

开启服务器,接收数据,回复响应:
在这里插入图片描述
客户端接收响应信息:
在这里插入图片描述
小知识点:中间层的概念,node作为中间层,比如node把Java的多个接口整合成一个接口。

HTTP爬虫 (Request)

先说下原则,能爬的爬,不能爬的不爬,反爬的绝对不能爬。

然后,下面用nodejs来实现网页内容的抓取,也就是简单的爬虫。
比如我们爬 https://www.microsoftstore.com.cn/ 这个网站的一些开元内容。

用到一个插件cheerio,是jquery核心功能简洁实现,主要是用在服务器端需要对DOM进行操作的地方。
安装:yarn add cheerio (可以先生成package.json文件,npm init -y 以便查看安装信息)

// 爬虫

const https=require('https');
const $ =require('cheerio');//引入cheerio模块

function filterData(data){
    // console.log("data:",data);//data是链接页面的html代码
    var items=$(data).find('.listContainerInner li');//类似选择器,找到要爬数据的唯一标识
    // console.log("items.length:",items.length);//5
    var result=[];//最有希望被爬出的数据以数组返回
    $(items).each((index,item)=>{
        // console.log("item:",item);
        // console.log("$(item):",$(item));//比item多了个"0",放在第一位
        // console.log($(item).find('.price strong').text());//能够把价格信息都拿到

        let $item=$(item);//不重新命名也行
        var param={
            url:$item.find('img').attr('data-src'),
            name:$(item).find('.name h4').text(),
            price:$item.find('.price strong').text(),
        }
        result.push(param);//把每一条拿出来数据以对象的形式每次放入数组
    })
    console.log(result);
    // return result;//以数组返回
}

var app=https.request({
    protocol:'https:',
    hostname:'www.microsoftstore.com.cn',
    port:443,//https的默认端口 
    method:'GET'
},(res)=>{
    var rawdata='';
    res.on('data',(chunk)=>{
        rawdata+=chunk;
    })
    res.on('end',()=>{
        // console.log(rawdata);//rawdata是链接页面的html代码
        filterData(rawdata);
    })
})

app.end();

我们想要把这五条数据的一些信息拿到手:
在这里插入图片描述
然后信息就拿到手啦:
在这里插入图片描述

登录、退出 小例子

// /api/login
// /api/logout

const http = require('http');
const qs = require('querystring');

http.createServer((req, res) => {
    var url = req.url;//用户请求路径
    var rawdata = '';
    console.log('method:',req.method);//查看请求方式是get还是post
    res.setHeader('Content-Type', 'application/json;charset:utf-8;');// 如果遇到字符乱码的问题,就设置文本类型
    req.on('data', (chunk) => {
        rawdata += chunk;
    })
    req.on('end', () => {
        // console.log(qs.parse(rawdata));//就相当于JSON.parse()
        console.log("url:",url);//判断是否登录或退出 /api/login
        console.log("rawdata:",rawdata);//客户端发过来的参数
        switch (url) {
            case '/api/login':
                let username = qs.parse(rawdata).username;//相当于JSON.parse(),尝试使用不同方法
                console.log(username);
                var result = {
                    code: 1,
                    message: '登陆成功',
                    username
                }
                res.end(JSON.stringify(result));//res.write()与res.end()的缩写版
                break;
            case '/api/logout':
                var result = {
                    code: 2,
                    message: '退出成功',
                }
                res.write(JSON.stringify(result));//跟JSON.stringify()功能一样
                res.end();
                break;
        }
    })
}).listen(3000, () => { // listen是绑定端口,监听端口
    console.log('正常启动 localhost 3000...');
})

介绍一款插件insomnia,用于前后端分离,可以模拟浏览器发送各种方式的请求。
登录login,客户端向服务端发送请求:
在这里插入图片描述
服务端:
在这里插入图片描述
退出logout,客户端退出登录:
在这里插入图片描述
服务端:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值