【一】浏览器的copy as fetch和copy as bash的区别
浏览器的copy as fetch和copy as bash的区别
位置:devTools->network->请求列表右键
copy as fetch
fetch("https://www.kuaishou.com/graphql", {"headers": {"accept": "*/*","accept-language": "en,zh-CN;q=0.9,zh;q=0.8","cache-control": "no-cache","content-type": "application/json","pragma": "no-cache","sec-ch-ua": "\"Google Chrome\";v=\"129\", \"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"129\"","sec-ch-ua-mobile": "?0","sec-ch-ua-platform": "\"Windows\"","sec-fetch-dest": "empty","sec-fetch-mode": "cors","sec-fetch-site": "same-origin"},"referrer": "https://www.kuaishou.com/search/video?searchKey=22","referrerPolicy": "unsafe-url","body": "{\"operationName\":\"visionSearchPhoto\",\"variables\":{\"keyword\":\"22\",\"pcursor\":\"\",\"page\":\"search\"},\"query\":\"fragment photoContent on PhotoEntity {\\n __typename\\n id\\n duration\\n caption\\n originCaption\\n likeCount\\n viewCount\\n commentCount\\n realLikeCount\\n coverUrl\\n photoUrl\\n photoH265Url\\n manifest\\n manifestH265\\n videoResource\\n coverUrls {\\n url\\n __typename\\n }\\n timestamp\\n expTag\\n animatedCoverUrl\\n distance\\n videoRatio\\n liked\\n stereoType\\n profileUserTopPhoto\\n musicBlocked\\n riskTagContent\\n riskTagUrl\\n}\\n\\nfragment recoPhotoFragment on recoPhotoEntity {\\n __typename\\n id\\n duration\\n caption\\n originCaption\\n likeCount\\n viewCount\\n commentCount\\n realLikeCount\\n coverUrl\\n photoUrl\\n photoH265Url\\n manifest\\n manifestH265\\n videoResource\\n coverUrls {\\n url\\n __typename\\n }\\n timestamp\\n expTag\\n animatedCoverUrl\\n distance\\n videoRatio\\n liked\\n stereoType\\n profileUserTopPhoto\\n musicBlocked\\n riskTagContent\\n riskTagUrl\\n}\\n\\nfragment feedContent on Feed {\\n type\\n author {\\n id\\n name\\n headerUrl\\n following\\n headerUrls {\\n url\\n __typename\\n }\\n __typename\\n }\\n photo {\\n ...photoContent\\n ...recoPhotoFragment\\n __typename\\n }\\n canAddComment\\n llsid\\n status\\n currentPcursor\\n tags {\\n type\\n name\\n __typename\\n }\\n __typename\\n}\\n\\nquery visionSearchPhoto($keyword: String, $pcursor: String, $searchSessionId: String, $page: String, $webPageArea: String) {\\n visionSearchPhoto(keyword: $keyword, pcursor: $pcursor, searchSessionId: $searchSessionId, page: $page, webPageArea: $webPageArea) {\\n result\\n llsid\\n webPageArea\\n feeds {\\n ...feedContent\\n __typename\\n }\\n searchSessionId\\n pcursor\\n aladdinBanner {\\n imgUrl\\n link\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}","method": "POST","mode": "cors","credentials": "include"
});
copy as bash
curl 'https://www.kuaishou.com/graphql' \-H 'Accept-Language: en,zh-CN;q=0.9,zh;q=0.8' \-H 'Cache-Control: no-cache' \-H 'Connection: keep-alive' \-H 'Cookie: weblogger_did=web_140476153E50FC40; kpf=PC_WEB; clientid=3; did=web_6c1bfef1bff5f0e063c16c6381ffc8d0; userId=1926344872; kuaishou.server.webday7_st=ChprdWFpc2hxxxxxxxxxxF5Ny5zdBKwAU-QhpLs58EqWw14KtRN3ktXeVV4IUBH-whoUB9UX3l00ZEd9B3n9SpIk9BsUuMCrjTDKxxxxxxxxxcCZg_WwoR6sy5p6VyZobi7CqqXtr-8XLF7slXPq8_PhjMjB5BRkekJPuKCZCSYTPMFYUWTr1AJEzk2Zt-eTtZox9VWK6XPjUUhVxxxxxxxxEG-4f5yJd10AXaDXiGhJglXWxx8RvW8kJJMTzKPTd1I8iIGnzLs4NhZYSpkCR8AmlC8W8L-ZzYA0UByzvqOerFQahKAUwAQ; kuaishou.server.webday7_ph=1b4a3594exxxxxxxxx3531408cb; kpn=KUAISHOU_VISION' \-H 'Origin: https://www.kuaishou.com' \-H 'Pragma: no-cache' \-H 'Referer: https://www.kuaishou.com/search/video?searchKey=22' \-H 'Sec-Fetch-Dest: empty' \-H 'Sec-Fetch-Mode: cors' \-H 'Sec-Fetch-Site: same-origin' \-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36' \-H 'accept: */*' \-H 'content-type: application/json' \-H 'sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"' \-H 'sec-ch-ua-mobile: ?0' \-H 'sec-ch-ua-platform: "Windows"' \--data-raw '{"operationName":"visionSearchPhoto","variables":{"keyword":"22","pcursor":"","page":"search"},"query":"fragment photoContent on PhotoEntity {\n __typename\n id\n duration\n caption\n originCaption\n likeCount\n viewCount\n commentCount\n realLikeCount\n coverUrl\n photoUrl\n photoH265Url\n manifest\n manifestH265\n videoResource\n coverUrls {\n url\n __typename\n }\n timestamp\n expTag\n animatedCoverUrl\n distance\n videoRatio\n liked\n stereoType\n profileUserTopPhoto\n musicBlocked\n riskTagContent\n riskTagUrl\n}\n\nfragment recoPhotoFragment on recoPhotoEntity {\n __typename\n id\n duration\n caption\n originCaption\n likeCount\n viewCount\n commentCount\n realLikeCount\n coverUrl\n photoUrl\n photoH265Url\n manifest\n manifestH265\n videoResource\n coverUrls {\n url\n __typename\n }\n timestamp\n expTag\n animatedCoverUrl\n distance\n videoRatio\n liked\n stereoType\n profileUserTopPhoto\n musicBlocked\n riskTagContent\n riskTagUrl\n}\n\nfragment feedContent on Feed {\n type\n author {\n id\n name\n headerUrl\n following\n headerUrls {\n url\n __typename\n }\n __typename\n }\n photo {\n ...photoContent\n ...recoPhotoFragment\n __typename\n }\n canAddComment\n llsid\n status\n currentPcursor\n tags {\n type\n name\n __typename\n }\n __typename\n}\n\nquery visionSearchPhoto($keyword: String, $pcursor: String, $searchSessionId: String, $page: String, $webPageArea: String) {\n visionSearchPhoto(keyword: $keyword, pcursor: $pcursor, searchSessionId: $searchSessionId, page: $page, webPageArea: $webPageArea) {\n result\n llsid\n webPageArea\n feeds {\n ...feedContent\n __typename\n }\n searchSessionId\n pcursor\n aladdinBanner {\n imgUrl\n link\n __typename\n }\n __typename\n }\n}\n"}'
两个代码片段分别是使用 JavaScript 的 fetch
API 和命令行工具 curl
发起的 POST 请求,目标均为快手的 GraphQL 接口 https://www.kuaishou.com/graphql
,用于搜索关键词为 22
的视频数据。以下是两者的核心区别:
1. 协议与用途
-
fetch
- 属于 浏览器原生 API,用于在前端(如网页脚本)中发起网络请求。
- 依赖浏览器环境,支持浏览器特有的功能(如
credentials: "include"
自动携带同源 Cookie)。
-
curl
- 是 命令行工具,用于在终端(如 Linux/macOS/Windows 的命令提示符)中模拟网络请求。
- 独立于浏览器,需手动指定所有请求参数(如 Cookie、User-Agent 等)。
2. 请求头(Headers)
-
共同点
- 核心请求头(如
Accept
、Content-Type
、Referer
、Sec-Fetch-*
等)几乎完全一致,均声明了请求为 JSON 格式、跨域模式(CORS)、来源为搜索页面https://www.kuaishou.com/search/video?searchKey=22
。
- 核心请求头(如
-
差异点
curl
额外包含:Cookie
头:显式携带浏览器存储的 Cookie(如用户登录状态、设备标识等),而fetch
中未显式声明,但通过credentials: "include"
会自动发送同源 Cookie。User-Agent
:明确指定浏览器指纹(Mozilla/5.0 (Windows NT 10.0...
),fetch
中浏览器会默认添加,但代码中未显式写出。Connection: keep-alive
:保持长连接,fetch
会自动处理,无需手动声明。
fetch
额外包含:referrerPolicy: "unsafe-url"
:控制 Referer 头的发送策略,curl
中无此参数(直接使用Referer
头)。
3. 请求体(Body)
- 内容完全一致:
均为 GraphQL 查询字符串,包含operationName
(visionSearchPhoto
)、搜索关键词keyword: "22"
、以及复杂的字段片段(fragment
),用于获取视频的详细信息(如 ID、播放量、封面链接等)。 - 格式差异:
fetch
中需将请求体转换为字符串("body": JSON.stringify(...)
,但用户代码中已直接使用字符串)。curl
中通过--data-raw
直接传递原始 JSON 数据,无需额外处理。
4. Cookie 处理
-
fetch
:- 通过
credentials: "include"
声明跨域请求时携带 Cookie(需目标域名支持Access-Control-Allow-Credentials: true
)。 - 浏览器自动读取当前域名下的 Cookie 并添加到请求中,代码中无需显式写入
Cookie
头。
- 通过
-
curl
:- 必须手动在
Cookie
头中写入完整的 Cookie 字符串(如用户提供的weblogger_did=...; kpf=PC_WEB; ...
),否则服务端可能无法识别用户状态(如登录信息)。
- 必须手动在
5. 使用场景
-
fetch
:- 用于前端代码(如网页脚本)中,动态获取数据并渲染页面(例如快手搜索结果页的视频列表)。
- 受浏览器同源策略、跨域限制(需服务端配置 CORS)。
-
curl
:- 用于调试、抓包分析(如通过浏览器开发者工具获取请求后,用
curl
复现)、自动化脚本(如爬虫、数据采集)。 - 可绕过浏览器限制,直接构造任意请求(需手动处理所有参数,包括签名、加密等)。
- 用于调试、抓包分析(如通过浏览器开发者工具获取请求后,用
总结
两者本质上是 同一请求的不同实现方式:fetch
是浏览器环境下的前端代码,依赖浏览器自动处理部分参数(如 Cookie、User-Agent);curl
是独立的命令行工具,需手动指定所有细节,适合调试和非浏览器环境下的请求模拟。核心差异在于 环境依赖、Cookie 处理方式 和 参数声明的显式程度。这段代码展示了两种向快手 GraphQL API 发送请求的方式,分别使用了浏览器的 fetch
API 和命令行工具 curl
。它们的主要区别包括:
-
运行环境
fetch
:在浏览器环境中执行,受浏览器安全策略限制(如 CORS)。curl
:在命令行或后端环境中执行,没有跨域限制。
-
Cookie 处理
fetch
:通过credentials: "include"
携带 cookies,但需要服务器明确允许(Access-Control-Allow-Credentials
)。curl
:直接在请求头中包含完整的 cookies(如weblogger_did
、userId
等),无需额外配置。
-
请求头差异
curl
包含了Connection: keep-alive
和完整的Cookie
信息。fetch
没有显式设置Connection
头,依赖浏览器默认行为。
-
数据格式
fetch
:使用 JavaScript 对象定义请求参数。curl
:使用命令行参数和原始字符串数据。
-
实际效果
fetch
:可能因缺少有效 cookies 或 CORS 配置失败。curl
:由于携带完整 cookies,更有可能成功获取数据。
总结:curl
请求更完整(包含 cookies),适合后端或脚本环境;fetch
请求需要浏览器环境支持,且需服务器配合 CORS 策略。如果直接运行,curl
更可能成功获取数据。