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 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, …}
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']
*/
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 heade
r, 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, 禁止转载 🈲️,侵权必究⚠️!
本文首发于博客园,作者:xgqfrms,原文链接:https://www.cnblogs.com/xgqfrms/p/17780326.html
未经授权禁止转载,违者必究!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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 运算符的执行顺序