xgqfrms™, xgqfrms® : xgqfrms's offical website of cnblogs! xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!

How to fix Fetch API GET request return an opaque response bug All In One

How to fix Fetch API GET request return an opaque response bug All In One

Status Code: 302 Found


fetch(`https://www.hulu.com/watch/78974b54-1feb-43ce-9a99-1c1e9e5fce3f`, {mode: "no-cors"})
.then(function (response) {
  console.log(`response`, response);
  // The API call was successful!
  return response.text();
})
.then(function (html) {
  // This is the HTML from our response as a text string
  console.log(html);
})
.catch(function (err) {
  // There was an error
  console.warn('Something went wrong.', err);
});

image

solutions

URL 重定向

https://www.hulu.com/watch/78974b54-1feb-43ce-9a99-1c1e9e5fce3f

https://www.hulu.com/movie/my-favorite-girlfriend-78974b54-1feb-43ce-9a99-1c1e9e5fce3f?entity_id=78974b54-1feb-43ce-9a99-1c1e9e5fce3f

Response Headers

Location: /movie/my-favorite-girlfriend-78974b54-1feb-43ce-9a99-1c1e9e5fce3f?entity_id=78974b54-1feb-43ce-9a99-1c1e9e5fce3f

  1. Node.js
import fs from "node:fs";
import path from "node:path";

/*

# Node.js server
$ node ./src/302.mjs

*/

// fetch(`https://www.hulu.com/watch/78974b54-1feb-43ce-9a99-1c1e9e5fce3f`, {mode: "no-cors"})
fetch(`https://www.hulu.com/watch/78974b54-1feb-43ce-9a99-1c1e9e5fce3f`)
.then(function (response) {
  // console.log(`response`, response);
  // console.log(`response.headers`, response.headers);
  // ❌ lost
  // console.log(`response.headers.location`, response.headers.get(`location`));
  for(const entry of response.headers.entries()) {
    console.log(`entry =`, entry);
  };
  // for(const key of response.headers.keys()) {
  //   console.log(`key =`, key);
  // };
  // for(const value of response.headers.values()) {
  //   console.log(`value =`, value);
  // };
  // The API call was successful!
  return response.text();
})
.then(function (html) {
  // This is the HTML from our response as a text string
  try {
    fs.writeFile(`./src/hulu.html`, html, (err) => {
      if(err) {
        console.log(`err`, err)
      }
    })
  } catch (error) {
    //
  }
  // <meta name="twitter:title" content="My Favorite Girlfriend"/>
  // <meta property="og:title" content="My Favorite Girlfriend"/>
  // console.log(html);
})
.catch(function (err) {
  // There was an error
  console.warn('Something went wrong.', err);
});


/*

entry = [ 'cache-control', 'no-store,no-cache' ]
entry = [ 'connection', 'keep-alive' ]
entry = [ 'content-encoding', 'gzip' ]
entry = [ 'content-length', '38245' ]
entry = [
  'content-security-policy',
  "upgrade-insecure-requests; frame-ancestors 'self' http://*.hulu.com https://*.hulu.com;"
]
entry = [ 'content-type', 'text/html; charset=utf-8' ]
entry = [ 'date', 'Sun, 22 Oct 2023 05:47:24 GMT' ]
entry = [ 'etag', 'W/"3db5e-9yp+6nU0bDgl0XxWSAgyyLrlfq8"' ]
entry = [ 'server', 'envoy' ]
entry = [
  'set-cookie',
  '_hulu_at=eyJhbGciOiJSUzI1NiJ9.eyJhc3NpZ25tZW50cyI6ImV5SjJNU0k2VzExOSIsInJlZnJlc2hfaW50ZXJ2YWwiOjg2NDAwMDAwLCJ0b2tlbl9pZCI6IjhiMzcwMzQ1LTY3ZDEtNGVhYS1hNTFlLTA1MGY5YTQxMjgzYSIsImFub255bW91c19pZCI6ImZlZDU1OGVhLTQ3NGMtNDg3Yy1iZWZjLWM0YzNlYzdhNjkyZSIsImlzc3VlZF9hdCI6MTY5Nzk1MzY0MzgwNSwidHRsIjozMTUzNjAwMDAwMCwiZGV2aWNlX3VwcGVyIjoxfQ.Rn9JItlFQmzciVTFsS_vzQBFhWq5d_fz0BEPRMHbaDB8grHAQ_j0LDF0I_JPVV-mzY36p_He9MAg_SZyplfLaX0RnpCPOJRv_2yAfbQb44p5MI2ITD7j5G1YliW8McVoK8tTSZVnQ-6EHObCKJds5KpSuDTIp5IhfCd3B--I2QhO60N8TYEi2jGe4ypvdSclrC3lXx9xG_lURuXz_Dzr-5cqyPlpPCOIDhYnhDSIBfbGU75wDX_Ltz4oftcoumiYsscnc6WAcWl87dSYrlfzSXF3NdqUHQF1roJH-5KeefmVXuzGDq0Vupuw8-1Ihqgoktfxi-3WcPoNLvWrMw-eNg;Path=/;Domain=.hulu.com;Expires=Mon, 21-Oct-2024 05:47:23 GMT;Max-Age=31536000;Secure, _hulu_assignments=eyJ2MSI6W119;Path=/;Domain=.hulu.com;Expires=Mon, 21-Oct-2024 05:47:23 GMT;Max-Age=31536000;Secure, ak_bmsc=4606FAC01852861E957866AC15B1D5C7~000000000000000000000000000000~YAAQbl7WF6QkHDmLAQAA9H3sVRUkODwViy+CrVU7GCx5JImUu8W1Xf/gka10kuwzRyStCSFyX9yrlp+xtvyEsmGfyeyC32wOtu8x8susVMzTa9d16I5PgopgoZWLYsJM0QqD7vWxBFNNj93LLrysnkXnG+rnYtZ997NeYyPvfldC8EndfX8Sf8MWcGalXUcgQllsjik8k1SDXwswwKmwWmU9SRfkplEzcg4/TXl+Ig3GgAG6dBXRfa++mKr7JNjUwDC23vMMckRUteoZy9cHmI/f+pcWC2fwjTSSDNQfYRFh4IzKcXWGEKX31MAHGX0DVOIWwQTpiPUUWDgmMbffudVBGtghKCi1y29LrZJuy+fByRjo49rf; Domain=.hulu.com; Path=/; Expires=Sun, 22 Oct 2023 07:47:23 GMT; Max-Age=7199; HttpOnly, bm_mi=E99FE0E13FED6E2144CE1422696761F3~YAAQbl7WF6UkHDmLAQAA9H3sVRWlbJ4gd1wDO4SePmGe9OhfUYpmca2UnjWA3F+w/UiuHD2stqAPxcFL0XV/Pfa16B8BE244E5/AXDaqpGZL/cbn8FODyiK2WW4c1MBhQrREQ73VnI3rvXVnQ+w8BjTe1NAUnJlK4v9ee8HwbnhXcRvVQIFSHjsGQuaBXwqxmbnUMZxNcFjFerWtNWgq+fsZg4PJpoNE51fJfz1fPuGFPvqiQhA2gdi7mFSAfMLstgL4mtzK1CWFHEm1FU3t2NbJZzIuCmvDhyHTrqP3QXulQMxtvL97POE6dSqoWvkF3fQdFd5HjTD6qHH5IMntX4v6/NZfHHtmaLEMGDV/wZnw9UbU12OEq/nHRdO9asymOJOCTjCyp+cfuOzMYw==~1; Domain=.hulu.com; Path=/; Expires=Sun, 22 Oct 2023 05:47:24 GMT; Max-Age=0; Secure'
]
entry = [ 'strict-transport-security', 'max-age=31536000' ]
entry = [ 'vary', 'Accept-Encoding, Origin' ]
entry = [ 'x-akamai-transformed', '9 45851 0 pmb=mTOE,2' ]
entry = [ 'x-datadog-parent-id', '9200498807994864342' ]
entry = [ 'x-datadog-sampled', '1' ]
entry = [ 'x-datadog-sampling-priority', '0' ]
entry = [ 'x-datadog-trace-id', '1699352624990999578' ]
entry = [ 'x-diproton-route', 'Envoy' ]
entry = [ 'x-envoy-upstream-service-time', '243' ]
entry = [ 'x-frame-options', 'DENY' ]

*/


  1. puppeteer / cheerio

爬取页面,解析 HTML

  1. regex
const html = `
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="twitter:card" content="summary"/>
    <meta name="twitter:title" content="My Favorite Girlfriend"/> ✅
    <meta name="twitter:site" content="@Hulu"/>
    <meta name="twitter:description" content="A chef&#x27;s life gets complicated when he falls for a beautiful young woman who has multiple personalities."/>
    <meta property="og:title" content="My Favorite Girlfriend"/> ✅
    <meta property="og:site_name" content="Hulu"/>
    <meta property="og:type" content="movie"/>
  </head>
</html>
`;


// ✅
// let result = html.match(/<meta name="twitter:title" content="([^"]+)"\/>/)
// ✅
// let result = html.match(/<meta name="twitter:title" content="([\w+\s?]+)"\/>/)
// let result = html.match(/<meta name="twitter:title" content="([\w+\s?]+)"\/>/)[0]
let result = html.match(/<meta name="twitter:title" content="([\w+\s?]+)"\/>/)[1]

console.log(`result =`, result);
// result = My Favorite Girlfriend


https://www.cnblogs.com/xgqfrms/p/17780516.html

demos

js read Response Headers bug

fetch(`https://www.hulu.com/watch/78974b54-1feb-43ce-9a99-1c1e9e5fce3f`, {mode: "no-cors"})
.then(function (response) {
  console.log(`response`, response.headers);
  console.log(`response.location`, response.headers.get(`location`));
  response.headers.forEach(function(value, name) {
    console.log(name + ": " + value);
  });
  // The API call was successful!
  return response.text();
})
.then(function (html) {
  // This is the HTML from our response as a text string
  console.log(html);
})
.catch(function (err) {
  // There was an error
  console.warn('Something went wrong.', err);
});

/*

response Headers {} [[Prototype]] : Headers append : ƒ append() delete : ƒ delete() entries : ƒ entries() forEach : ƒ forEach() get : ƒ () getSetCookie : ƒ getSetCookie() has : ƒ has() keys : ƒ keys() set : ƒ () values : ƒ values() constructor : ƒ Headers() Symbol(Symbol.iterator) : ƒ entries() Symbol(Symbol.toStringTag) : "Headers" [[Prototype]] : Object

*/

error ❌

fetch(`https://www.hulu.com/watch/78974b54-1feb-43ce-9a99-1c1e9e5fce3f`, {mode: "no-cors"})
.then(function (response) {
  console.log(`response`, response);
  console.log(`response.headers`, response.headers);
  console.log(`response.headers.location`, response.headers.get(`location`));
  for(const entry of response.headers.entries()) {
    console.log(`entry =`, entry);
  };
  for(const key of response.headers.keys()) {
    console.log(`key =`, key);
  };
  for(const value of response.headers.values()) {
    console.log(`value =`, value);
  };
  // The API call was successful!
  return response.text();
})
.then(function (html) {
  // This is the HTML from our response as a text string
  console.log(html);
})
.catch(function (err) {
  // There was an error
  console.warn('Something went wrong.', err);
});


// response Response {type: 'opaque', url: '', redirected: false, status: 0, ok: false, …}

image

OK ✅

fetch(`https://developer.mozilla.org/en-US/docs/Web/API/Response/headers`, {mode: "no-cors"})
.then(function (response) {
  console.log(`response`, response);
  console.log(`response.headers`, response.headers);
  console.log(`response.headers.location`, response.headers.get(`location`));
  for(const entry of response.headers.entries()) {
    console.log(`entry =`, entry);
  };
  for(const key of response.headers.keys()) {
    console.log(`key =`, key);
  };
  for(const value of response.headers.values()) {
    console.log(`value =`, value);
  };
  // The API call was successful!
  return response.text();
})
.then(function (html) {
  // This is the HTML from our response as a text string
  console.log(html);
})
.catch(function (err) {
  // There was an error
  console.warn('Something went wrong.', err);
});

/*

response Response {type: 'basic', url: 'https://developer.mozilla.org/en-US/docs/Web/API/Response/headers', redirected: false, status: 200, ok: true, …}

entry = (2) ['accept-ranges', 'none']
entry = (2) ['alt-svc', 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000, clear']
entry = (2) ['cache-control', 'public, max-age=3600']
entry = (2) ['content-encoding', 'br']
entry = (2) ['content-security-policy', "default-src 'self'; script-src 'report-sample' 'se…mozilla.net; child-src 'self'; worker-src 'self';"]
entry = (2) ['content-type', 'text/html']
entry = (2) ['date', 'Sun, 22 Oct 2023 05:19:01 GMT']
entry = (2) ['etag', 'W/"fb636dcadfbfc4da060077d4f831b6dd"']
entry = (2) ['expires', 'Sun, 22 Oct 2023 06:19:01 GMT']
entry = (2) ['last-modified', 'Fri, 20 Oct 2023 00:33:21 GMT']
entry = (2) ['server', 'Google Frontend']
entry = (2) ['vary', 'Accept-Encoding']
entry = (2) ['via', '1.1 google']
entry = (2) ['x-cache', 'miss']
entry = (2) ['x-cloud-trace-context', '1f4f2b6a0185ba6fec42b256f1b13879']
entry = (2) ['x-content-type-options', 'nosniff']
entry = (2) ['x-frame-options', 'DENY']
entry = (2) ['x-goog-generation', '1697762001607686']
entry = (2) ['x-goog-hash', 'crc32c=4kEQ6Q==, md5=+2Ntyt+/xNoGAHfU+DG23Q==']
entry = (2) ['x-goog-meta-goog-reserved-file-mtime', '1697761579']
entry = (2) ['x-goog-metageneration', '1']
entry = (2) ['x-goog-storage-class', 'STANDARD']
entry = (2) ['x-goog-stored-content-encoding', 'identity']
entry = (2) ['x-goog-stored-content-length', '49558']
entry = (2) ['x-guploader-uploadid', 'ABPtcPpmHdDr9dkg-ADS55VYkPe-PELjIEQjK06aT4HjnHDQTSUOAz0Rtd8wYw6oCSnk0vg14u9_IlbGGTGcxLH3iAT5kUOL-mkf']


*/

image

Access-Control-Expose-Headers

Access-Control-Expose-Headers: [<header-name>[, <header-name>]*]
Access-Control-Expose-Headers: *

The Access-Control-Expose-Headers response header allows a server to indicate which response headers should be made available to scripts running in the browser, in response to a cross-origin request.

响应标头 Access-Control-Expose-Headers 允许服务器指示那些响应标头可以暴露给浏览器中运行的脚本,以响应跨源请求

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers

The browser will not allow to expose the Authorization header, unless if the Backend told the browser to expose it explicitly.

https://stackoverflow.com/a/66291644/5934465

Response

https://developer.mozilla.org/en-US/docs/Web/API/Response

Headers

https://developer.mozilla.org/en-US/docs/Web/API/Headers

refs

How to use regular expression to match a special meta tag in html string using javascript All In One

https://www.cnblogs.com/xgqfrms/p/17780516.html

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

https://stackoverflow.com/questions/77338662/programmaticaly-get-movie-name-from-hulu-url



©xgqfrms 2012-2025

www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!

原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!


posted @   xgqfrms  阅读(25)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2022-10-22 TypeScript infer keyword All In One
2021-10-22 js 循环多次和循环一次的时间的性能对比 All In One
2020-10-22 使用 js 实现一个简易版的 GIPHY 动图搜索 web 应用程序
2020-10-22 使用 js 实现一个简易版的动画库
2020-10-22 使用 js 实现一个简易版的 drag & drop 库
2020-10-22 使用 js 实现一个简易版的 async 库
2020-10-22 js 运算符的执行顺序
点击右上角即可分享
微信分享提示