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

(🐞 反爬虫测试!打击盗版⚠️)如果你看到这个信息, 说明这是一篇剽窃的文章,请访问 https://www.cnblogs.com/xgqfrms/ 查看原创文章!

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-2021

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

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


posted @ 2023-10-22 13:08  xgqfrms  阅读(10)  评论(1编辑  收藏  举报