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);
});

solutions
URL 重定向
https://www.hulu.com/watch/78974b54-1feb-43ce-9a99-1c1e9e5fce3f
Response Headers✅
Location: /movie/my-favorite-girlfriend-78974b54-1feb-43ce-9a99-1c1e9e5fce3f?entity_id=78974b54-1feb-43ce-9a99-1c1e9e5fce3f
- 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' ]
*/
- puppeteer / cheerio
爬取页面,解析 HTML
- 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'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 Headersbug
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, …}

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']
*/

(🐞 反爬虫测试!打击盗版⚠️)如果你看到这个信息, 说明这是一篇剽窃的文章,请访问 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, 禁止转载 🈲️,侵权必究⚠️!
本文首发于博客园,作者:xgqfrms,原文链接:https://www.cnblogs.com/xgqfrms/p/17780326.html
未经授权禁止转载,违者必究!

浙公网安备 33010602011771号