首页 > 解决方案 > Node-Fetch POST 返回与 Firefox POST 不同的结果

问题描述

我能够使用 Firefox 成功登录网站,但无法使用 node-fetch 复制该登录。登录过程分为三个阶段:

  1. 转到 /login 和网站以 sessionToken 响应(这部分工作正常)
  2. 在 sessionToken 旁边输入电子邮件和密码,网站以 sessionToken 和 authToken 响应(这是我遇到问题的部分)
  3. 使用 sessionToken 和 authToken 向 /portal 请求,网站以我尝试访问的 HTML 响应

在 Firefox 开发工具中,我可以看到工作标头和工作请求正文。当我在开发工具中单击“请求”时,我会看到一个“表单数据”标题,其中包含“电子邮件”和“密码”的正确值。当我在开发工具中单击“标题”时,这是成功的 Firefox 请求:

POST /login/action HTTP/2
Host: www.website.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 46
Origin: https://www.website.com
Connection: keep-alive
Referer: https://www.website.com/login
Cookie: _sessiontoken=sessionTokenHere
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
TE: trailers

在 Firefox 上,它会返回带有以下标头的 302(重定向)响应:

HTTP/2 302 Found
date: Sun, 31 Oct 2021 17:25:03 GMT
content-type: text/html; charset=utf-8
cache-control: no-cache
location: https://www.website.com/portal
x-runtime: 9
set-cookie: auth_token=authtokenHere; path=/
set-cookie: 
set-cookie: _sessiontoken=sessionTokenHere; path=/; HttpOnly
cf-cache-status: DYNAMIC
[omitted for brevity: expect-ct, report-to, nel, server, cf-ray, alt-svc, X-Firefox-Spdy]

现在,这是我尝试在 node.js 中与 node-fetch 一起使用的 POST 选项:

{
method: 'POST', headers: {
Host: 'www.website.com'
,'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0'
,Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate, br',
'Content-Length': 46,
Origin: 'https://www.website.com',
Connection: 'keep-alive',
Referer: 'https://www.website.com/login',
Cookie: '_sessiontoken=sessionTokenHere'
'Upgrade-Insecure-Requests': '1',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-User': '?1',
TE: 'trailers',
body: URLSearchParams { 'email' => 'myEmail','password' => 'myPassword'}

但是,当使用带有上述选项的 node-fetch 时,它返回 200,而不是 302。以下是该响应的标头(通过 fetch() 函数中的 console.log() 打印):

 [Object: null prototype] {
date: [ 'Sun, 31 Oct 2021 18:12:01 GMT' ],
'content-type': [ 'text/html; charset=utf-8' ],
'transfer-encoding': [ 'chunked' ],
connection: [ 'keep-alive' ],
vary: [ 'Accept-Encoding' ],
'x-runtime': [ '5' ],
'cache-control': [ 'private, max-age=0, must-revalidate' ],
 'set-cookie': [
'_sessionToken=sessionTokenHere; path=/; HttpOnly'
],
'cf-cache-status': [ 'DYNAMIC' ],
'content-encoding': [ 'br' ],
[omitted for brevity: expect-ct, report-to, nel, server, cf-ray, alt-svc]
}

我很困惑为什么它可以在 Firefox 中工作,但不能在 node-fetch 中工作。几点注意事项:

标签: javascripthtmlhttpweb-scrapingfetch

解决方案


node-fetch自动跟随重定向。它将自动转到下一个重定向的 url(Locationhttp 标头值)。

如果您想捕捉 301 或 302 呼叫,您可以在选项中设置redirect属性为,这样您就可以自己管理重定向manualredirect: "manual"

例如,以下代码将捕获调用(理论上301它会为您做同样的事情,在此处实现):302

const fetch = require("node-fetch");

(async () => {
  const response = await fetch("https://stackoverflow.com/users/2614364", {
    redirect: "manual",
  });
  console.log(response.status);
  console.log(response.headers.get("set-cookie"));
})();

我想你想使用response.headers.get("set-cookie")


推荐阅读