node防盗链与反防盗链

1,334 阅读3分钟

让你明明白白学知识,有代码,有讲解,抄的走,学的会!

我们可能会遇到,需要爬取图片的小需求,以下的案例,是通过node原生API去爬取图片的过程,这个本来是我去爬取一个有防盗链服务的图片,那么,通过构造一个合法的请求头,依旧可以爬取图片

反防盗链,通过构建成一样的http请求, 达到趴取有防盗链的接口/网站 的目的

node反防盗链源码

getRefererImg.js

/* 
反防盗链

防盗链的服务 referer.js这个起在 localhost:3004

对 lisi.com这个域名是在白名单的,是被允许的,端口是 3004,下面构造成一样的请求头,即可
*/
const fs = require('fs')
const http = require('http')
const path = require('path')

const opt = {
  hostname: 'zhangsan.com',
  host: 'zhangsan.com',
  port: 3004,
  headers: {
    // 请求头伪造成能通过的 referer和host,这2个一定要要趴取的网站的一样
    Host: 'lisi.com:3004',
    Referer: 'lisi.com',
  },
  path: '/img/a.jpg',
  method: 'GET'
}

let req = http.request(opt, (res) => {
  let data = ''
  // 一定要设置response的编码为binary否则会下载下来的图片打不开
  res.setEncoding("binary");
  res.on('data', chunk => {
    data += chunk
  })

  res.on('end', () => {
    let p = path.join(__dirname, 'public/img/pa.jpg')
    
    // 把二进制写成文件
    fs.writeFile(p, data, "binary",err => {
      if (err) {
        console.log('这里发生错误')
        throw err
      }
      console.log('趴取图片成功')
    })
  })
})

req.on('error', (err) => {
  console.log('发送请求,发生错误')
  console.log(err)
})

req.end()

node防盗链源码

下面附上防盗链案例的源码

原理: 利用HTTP中的 host和referer实现图片防盗链

/**
 * 本案例演示node+express实现防盗链
 * 原生Node也是没问题的,就是要处理静态资源,处理页面请求路由,再判断资源请求头
 * 
 * 使用express 就可以省略对静态资源(图片),页面地址的请求处理
 */

const express = require('express')
const router = express.Router()
const app = express()

const path = require('path')
const url = require('url')
const logger = require('morgan')
const chalk = require('chalk')
const fs = require('fs')

// 白名单地址
const whiteList = ['lisi.com']
const imgExt = ['.jpg', '.jpeg', '.png', '.gif', 'bmp']

// 防盗链中间件
app.use((req, res, next) => {
  // 获取到请求头
  let headers = req.headers
  let referer = headers['referer'] || headers['referered']
  
  console.log(chalk.red("referer-->"+referer))

  if (referer) {

    // 不是图片资源,直接放行
    if (!isImg(req.url)) {
      next()
    } else {
      console.log("请求地址--》",req.url)
      // 请求资源存在referer 做防盗链处理
      let referHost = url.parse(referer).hostname
      let host = req.headers.host.split(":")[0]
      console.log(chalk.red('host-->', host, "referHost-->", referHost))

      if (referHost !== host) {
        // 请求地址在不在白名单里
        let isInWhiteList = whiteList.includes(host)
        console.log('是否在白名单里面', isInWhiteList)
        // 直接放行
        if (isInWhiteList) {
          next()
        } else {
          // 图片直接给一个其他的代替
          const errorImg = path.join(__dirname, 'public/img/b.jpg')

          fs.readFile(errorImg, (err, data) => {
            if(err) throw err

            res.end(data)
          })
        }
      } else {
        // 同一个站点
        next()
      }
    }

  } else {
    // 直接过, 是本网站的
    next()
  }
})

app.use(express.static(path.join(__dirname, 'public')))
app.use(router)
app.use(logger('dev'))

app.listen(3004, () => {
  console.log(`http://localhost:3004`)
})

// 判断是不是图片
function isImg (url) {
  let ext = path.parse(url).ext

  if (!ext) return false

  return imgExt.includes(ext)
}

这个案例是本地映射的域名,window下怎么添加本地自定义域名?

我们在本地的机器上添加2个自定义域名,我们知道,域名是会被解析成IP的,所以,我们将自定义域名指向127.0.0.1就可以

具体操作

1、 window路径地址: 打开 C:\Windows\System32\drivers\etc 中的hosts文件,如果没有,就创建一个

2、没有hosts文件的,直接 cmd 创建一个 使用: type nul>hosts 命令

3、在hosts文件中添加2个自定义域名

127.0.0.1 zhangsan.com
127.0.0.1 lisi.com

4、 可能会遇到配置本地域名以后, 能通过 ping zhangsan.com 但是不能通过浏览器访问, 使用以下方式

  • cmd控制台 执行 ipconfig /flushdns 刷新dns
  • 重启浏览器