返回博客
指南
Mihnea-Octavian ManolacheLast updated on Mar 31, 20262 min read

如何使用 Axios 设置 HTTP 头部以规避检测

如何使用 Axios 设置 HTTP 头部以规避检测

HTTP 头部是任何 HTTP 请求或响应的重要组成部分,因为它们允许客户端和服务器就请求交换额外信息。在构建 Node.js Web 应用程序时,拥有一个可靠且易于使用的 HTTP 客户端来向 API 和其他服务器发送请求至关重要。

在 HTTP 客户端方面,JavaScript 和 Node.js 提供了相当多的选择。然而,我个人最喜欢的一个(无疑也是前五名的 JavaScript HTTP 客户端之一)是 Axios。因此,今天我们将重点探讨如何在 Axios 中设置 HTTP 头部。

Axios 是一款广泛使用的 JavaScript 库,它简化了 HTTP 请求的过程,在 Node.js 环境中处理 API 时尤为实用。本文将探讨 Axios 处理 HTTP 头信息的多种方法。读完本文后,您将能够理解:

  • 什么是 HTTP 头部以及它们如何工作
  • 为何 Axios 是 JavaScript 的优秀 HTTP 客户端
  • 如何在真实的 Web 应用中使用 Axios 处理 HTTP 头部

HTTP 通信的工作原理

在深入探讨 HTTP 头部的定义之前,我认为至少需要对 HTTP 协议的工作原理有一个概览。相信您已经知道,超文本传输协议(HTTP)是当今网络构建的基础。从宏观层面来看,它允许信息在服务器与其客户端之间进行传输。这种信息交换的实际流程大致如下:

  • 客户端建立新的 TCP 连接
  • 客户端向服务器发送一条消息,即 HTTP 请求
  • 服务器接收并解析该请求
  • 随后向客户端发送一条消息,即 HTTP 响应
  • 客户端读取消息,并继续保持或关闭连接

今天我们将重点关注的消息部分,特别是客户端发送的消息。为了使服务器与客户端之间的通信高效,消息必须按照 HTTP 协议的规定进行格式化。就 HTTP 请求而言,构成消息的元素包括:

方法描述了我们希望通过请求执行什么操作(例如接收、发送或更新信息等)

  • 路径,即我们试图访问的 URL 地址
  • 版本:我们所使用的 HTTP 协议
  • HTTP 头部,用于在请求中附加额外信息和元数据
  • 正文(Body):当使用向服务器发送信息的方法时(例如 POST 请求)

什么是 Axios 中的 HTTP 头部,它们如何工作

简而言之,HTTP 头部是向消息传递额外信息和元数据的字段。 这里所说的“消息”,既指客户端发送的请求,也指服务器发送的响应。因此,服务器和客户端都可以发送和接收头部。例如,假设你想与服务器建立持久连接。默认情况下,HTTP 连接会在每次请求后关闭。要避免这种情况,你只需发送 `Keep-Alive` 头部即可。

在 Axios 中使用 HTTP 头部其实并没有什么特别之处。正如我们所讨论的,Axios 是一个 HTTP 客户端,而我们已经明确了 HTTP 客户端可以发送和接收头部。

为何 Axios 是 JavaScript 的优秀 HTTP 客户端

既然我们已经简要了解了 HTTP 的工作原理,接下来就来谈谈“客户端”。JavaScript 提供了几种通过 HTTP 与服务器“程序化交互”的选项。在最受欢迎的选择中,有 `axios`、`node-fetch` 和 `got`。

在 JavaScript 社区中,关于该选用哪一款存在不同看法。当然,每个包都有其优缺点,但我自己在对这三者进行简单的速度测试后,选择了 Axios。

以下是我用于测试速度的脚本:

// index.js

import { get_timing, array_sum } from './helpers.js'

import got from 'got'

import axios from 'axios'

const CALLS = 5

const send = async () => {

   const res = {}

  

   let start = process.hrtime()

   await got('https://httpbin.org/')

   const g = get_timing(start)

   res.got = g

   start = process.hrtime()

   await axios.get('https://httpbin.org/')

   const a = get_timing(start)

   res.axios = a

   start = process.hrtime()

   await fetch('https://httpbin.org/')

   const f = get_timing(start)

   res.fetch = f

   return res

}

let test_results = {

   got: [],

   axios: [],

   fetch: []

}

let avg = {}

console.log(`[i] Process started with ${CALLS} iterations.`)

for (let i = 0; i<=CALLS; i++) {

   let r = await send()

   Object.entries(test_results).map(([key, value]) => test_results[key].push(r[key]))

}

Object.entries(test_results).forEach(([key, value]) => {

       console.log(`\n[+] ${key}`)

       console.log(`    [i] Average: ${array_sum(value)/value.length}`)

       console.log(`    [i] Values: ${value}`)

       avg[key] = array_sum(value)/value.length

   }

)

console.log(`\n🚀🚀🚀 WINNER: ${Object.keys(avg).reduce((key, v) => avg[v] < avg[key] ? v : key)}  [${CALLS} calls sent] 🚀🚀🚀`)

以下是 `helper` 函数:

// helpers.js

export const get_timing = (start) => {

   const NS_PER_SEC = 1e9

   const NS_TO_MS = 1e6

   const diff = process.hrtime(start)

   return (diff[0] * NS_PER_SEC + diff[1]) / NS_TO_MS

}

export const array_sum = (array) => {

   return array.reduce((accumulator, value) => {

     return accumulator + value

   }, 0)

}

我分别使用这三个包发送了 5、10、20 和 30 次请求,每次迭代 10 次,以下是结果概览:

这里所说的“迭代”指的是脚本的执行次数,我使用了这个 Bash 公式,它会生成一个 .txt 文件,记录每次迭代的结果:

~ » for i in {1..10}

do

node got.js > "${i}.txt"

echo "${i} done"

done

如您查看详细结果表所见,每批次的耗时各不相同,有时 Axios 并非最快。 不过总体而言,Axios 的平均响应时间为 387 毫秒,比竞争对手快了半秒。Got 和 Fetch 的响应时间非常接近,平均约为 435 毫秒。综上所述,如果速度对您的项目至关重要,Axios 或许是您最理想的 HTTP 客户端。

如何使用 Axios 发送 HTTP 头部

我个人认为,实践出真知,效果立竿见影。既然我们已经掌握了发送 HTTP 头部的知识和工具,那就开始动手做一个小项目吧。在本节中,我们将创建一个新的 Node 项目,安装 Axios,并使用它向服务器发送 HTTP 头部。

项目设置

在继续之前,请确保您的机器已安装:

提示:您可以在终端中输入以下命令,检查是否已安装 Node.js:

~ » node -v

v19.3.0

现在,让我们创建一个新文件夹并在 IDE 中打开它。如果您使用的是类 UNIX 系统(Mac 或 Linux),可以在终端中输入以下命令,通过命令行创建新目录:

~ » mkdir axios_project && cd axios_project

~ » npm init -y

~ » npm i axios

~ » touch index.js

~ » code .

这些命令将:

  • 创建一个新目录(命名为“axios_project”)并进入该目录
  • 在该目录内初始化一个新的 Node.js 项目
  • 在项目中安装 `axios`
  • 创建一个新的 ‘index.js’ 文件
  • 在当前项目中打开您的 IDE

学习代码

实际上,使用 Axios 发送 HTTP 头部有几种方法。例如,您可以按照此处的描述使用配置对象,或者使用实例方法,这些方法会自动将您传递的配置与实例配置合并。您还可以使用 `axios.defaults.headers.common` 对象为所有 Axios 请求设置默认头部。

此外,请注意 Axios 是一个基于 Promise 的 HTTP 客户端。这意味着我们需要在异步函数中等待请求完成,或者手动解析响应。

考虑到这两个方面,让我们开始实际编写代码。我们将使用 ‘index.js’ 文件进行操作。为方便起见,让我们先回顾一下需要做的事情:

  • 在文件中导入 `axios`
  • 定义一个用于存储请求头信息的配置对象
  • 将配置传递给 `axios` 以发起请求
  • 在终端中输出响应

#1:使用配置对象发送 GET 请求

import axios from "axios"

const config = {

   method: 'GET',

   url: 'https://httpbin.org/headers',

   headers: {

       'HTTP-Axios-Headers': 'This is my custom header.'

   }

}

axios(config)

   .then((response) => {

       console.log(response)

   })

   .catch((err) => {

       console.log(err)

   })

使用 Axios 发送 HTTP 头部再简单不过了。要执行此脚本,只需在终端中运行以下命令:

~ » node index.js  

{

  status: 200,

  statusText: 'OK',

  headers: ...,

  config: ...,

  request: ...,

  data: {

    headers: {

      'Accept': 'application/json, text/plain, */*',

      'Accept-Encoding': 'gzip, compress, deflate, br',

      'Host': 'httpbin.org',

      'Http-Axios-Headers': 'This is my custom header.',

      'User-Agent': 'axios/1.2.2',

      'X-Amzn-Trace-Id': 'Root=1-63b54d94-7656f02113483dfa036c476c'

    }

  }

}

整个响应数据量较大,且遵循以下结构。不过,我们主要关注的是 `data` 字段,它包含从服务器接收到的实际响应。现在请查看上方的响应。请记住,我们向服务器发送了自定义标头 `Http-Axios-Headers`,如您所见,服务器确实接收到了该标头。

#2:使用方法别名发送 POST 请求

import axios from "axios"

const data = {

   'foo':'bar'

}

const config = {

   headers: {

       'HTTP-Axios-Headers': 'This is my custom header.'

   }

}

axios.post('http://httpbin.org/post', data, config)

   .then(response => console.log(response.data))

   .catch(err => console.log(err))

请注意,为了发送 POST 请求,我在脚本中添加了一个新的 `data` 对象,并修改了 URL。现在,如果你运行该脚本,你会发现这是从服务器接收到的数据:

{

  args: {},

  data: '{"foo":"bar"}',

  files: {},

  form: {},

  headers: {

    Accept: 'application/json, text/plain, */*',

    'Accept-Encoding': 'gzip, compress, deflate, br',

    'Content-Length': '13',

    'Content-Type': 'application/json',

    Host: 'httpbin.org',

    'Http-Axios-Headers': 'This is my custom header.',

    'User-Agent': 'axios/1.2.2',

    'X-Amzn-Trace-Id': 'Root=1-63b5508a-3a86493f087662d3169e80ee'

  },

  json: { foo: 'bar' },

  origin: '49.12.221.20',

  url: 'http://httpbin.org/post'

}

如何在 Axios 中使用 HTTP 头部进行网页抓取

如果您计划使用 Axios 进行网页抓取,请注意大多数网站都设有防护规则,会拦截来自自动化软件(包括网页抓取工具)的请求。

使用 HTTP 头部(特别是 `User-Agent` 头部)是网页抓取时规避检测的有效技巧。User-Agent 头部向服务器标识客户端的浏览器和操作系统,而 Web 服务器可能会根据这些信息提供不同的内容或阻止请求。通过设置 User-Agent 头部,你可以模拟常见的 Web 浏览器,从而增加绕过某些检测机制的几率。

以下是一个使用 Axios 配合 User-Agent 头部在网页抓取时规避检测的示例:

import axios from "axios"

axios.defaults.headers.common['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'

axios({

   method: 'GET',

   url: 'https://httpbin.org/get',

}).then(response => {

   console.log(response.data)

});

请注意,这次我使用了 Axios 的 config defaults 选项,该选项会将该标头应用于所有后续请求。在此示例中,User-Agent 标头被设置为模拟运行在 Windows 10 操作系统上的 Chrome 浏览器。您可以尝试使用不同的 User-Agent 值或多种不同的标头,以找出最适合您具体用例的方案。

值得注意的是,虽然更改 User-Agent 头部在某些情况下可能有助于避免被检测,但这并非万无一失的方法,Web 服务器仍可能识别出您正在使用 Web 爬虫。因此,建议结合多种技术手段来避免被检测,并确保遵守网站的服务条款。

结论

在 Axios(或其他任何 HTTP 客户端)中使用 HTTP 头部可以提高服务器与客户端之间的通信效率。此外,在构建网络爬虫时,这甚至有助于避免被检测。事实上,在 WebScrapingAPI,我们正将使用各种用户代理作为基本规避技术之一。

当然,检测机制不仅限于用户代理,但这确实是一个不错的切入点。这里有一篇关于如何在网页抓取时避免IP地址被封禁的精彩教程,它将帮助您更好地理解规避机制的运作原理。

另外,您知道 Web Scraping API 允许您在请求中设置自定义头部信息吗?如果不知道,请点击此处了解更多详情。

关于作者
Mihnea-Octavian Manolache, 全栈开发工程师 @ WebScrapingAPI
Mihnea-Octavian Manolache全栈开发工程师

Mihnea-Octavian Manolache 是 WebScrapingAPI 的全栈及 DevOps 工程师,负责开发产品功能并维护确保平台平稳运行的基础设施。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网络数据。