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