curl调用Doordash GraphQL接口正常,其他工具请求返回403问题排查
解决Doordash GraphQL接口curl正常但其他工具返回403的问题
可能的原因与解决思路
1. 请求头不完整或不一致
- 终端curl可能自动携带了部分隐含请求头(如
Accept-Encoding),或者你复制的curl命令包含了浏览器会话的Cookie,而其他工具未添加这些关键头。 - 用
curl -v <你的curl命令>查看完整请求头,对比Postman/requests的请求头,确保所有字段完全匹配,特别是Cookie、user-agent、content-type。
2. 请求体编码或格式差异
- curl的
--data-raw $'...'使用shell转义处理了字符串中的换行和特殊字符,其他工具可能因编码问题导致请求体与curl不一致。 - 验证方法:将curl的请求体复制到其他工具时,确保换行、转义字符(如
\u0021)完全保留;Python中建议用json参数传入payload,避免手动编码出错。
3. 会话Cookie缺失
- Doordash的接口可能需要有效的会话Cookie才能通过验证,curl命令如果是从浏览器复制的,通常包含当前登录状态的Cookie,而其他工具默认没有携带。
- 解决:从浏览器开发者工具的"网络"面板中复制完整的Cookie字符串,添加到请求头的
Cookie字段中。
4. TLS客户端指纹识别
- 部分网站会通过TLS握手参数识别请求来源,curl、浏览器与其他工具的TLS指纹不同,可能被判定为非合法请求拦截。
- 解决:Python中可使用
curl_cffi库模拟curl的TLS指纹;Postman可尝试开启"模拟浏览器请求"的相关设置,调整TLS版本匹配浏览器。
5. 压缩设置差异
- curl的
--compressed参数会自动处理gzip/deflate压缩,确保其他工具也开启了相应的压缩支持(Python requests默认支持,Postman需在设置中启用)。
Python requests示例代码
import requests url = "https://www.doordash.com/graphql/searchWithFilterFacetFeed?operation=searchWithFilterFacetFeed" headers = { 'authority': 'www.doordash.com', 'accept': '*/*', 'accept-language': 'en-US', 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36', # 替换为你从浏览器复制的Cookie 'Cookie': 'your_session_cookie_here' } payload = { "operationName": "searchWithFilterFacetFeed", "variables": { "cursor": "eyJvZmZzZXQiOjUwLCJ2ZXJ0aWNhbF9pZHMiOltdLCJjcm9zc192ZXJ0aWNhbF9wYWdlX3R5cGUiOiJHTE9CQUxfU0VBUkNIX1BBR0UiLCJwYWdlX3N0YWNrX3RyYWNlIjpbXSwibGF5b3V0X292ZXJyaWRlIjoiVU5TUEVDSUZJRUQiLCJpc19wYWdpbmF0aW9uX2ZhbGxiYWNrIjpudWxsLCJzb3VyY2VfcGFnZV90eXBlIjpudWxsLCJ2ZXJ0aWNhbF9uYW1lcyI6e319", "filterQuery": "", "query": "street food", "isDebug": False }, "query": "query searchWithFilterFacetFeed($cursor: String, $filterQuery: String, $query: String!, $isDebug: Boolean, $fromFilterChange: Boolean, $serializedBundleGlobalSearchContext: String, $address: String) {\n searchWithFilterFacetFeed(\n cursor: $cursor\n filterQuery: $filterQuery\n query: $query\n isDebug: $isDebug\n fromFilterChange: $fromFilterChange\n serializedBundleGlobalSearchContext: $serializedBundleGlobalSearchContext\n address: $address\n ) {\n ...FacetFeedV2ResultFragment\n __typename\n }\n}\n\nfragment FacetFeedV2ResultFragment on FacetFeedV2Result {\n body {\n id\n header {\n ...FacetV2Fragment\n __typename\n }\n body {\n ...FacetV2Fragment\n __typename\n }\n layout {\n omitFooter\n __typename\n }\n __typename\n }\n page {\n ...FacetV2PageFragment\n __typename\n }\n header {\n ...FacetV2Fragment\n __typename\n }\n custom\n logging\n __typename\n}\n\nfragment FacetV2Fragment on FacetV2 {\n ...FacetV2BaseFragment\n childrenMap {\n ...FacetV2BaseFragment\n __typename\n }\n __typename\n}\n\nfragment FacetV2BaseFragment on FacetV2 {\n id\n childrenCount\n component {\n ...FacetV2ComponentFragment\n __typename\n }\n name\n text {\n ...FacetV2TextFragment\n __typename\n }\n images {\n main {\n ...FacetV2ImageFragment\n __typename\n }\n icon {\n ...FacetV2ImageFragment\n __typename\n }\n background {\n ...FacetV2ImageFragment\n __typename\n }\n accessory {\n ...FacetV2ImageFragment\n __typename\n }\n custom {\n key\n value {\n ...FacetV2ImageFragment\n __typename\n }\n __typename\n }\n __typename\n }\n events {\n click {\n name\n data\n __typename\n }\n __typename\n }\n style {\n spacing\n background_color\n border {\n color\n width\n style\n __typename\n }\n sizeClass\n __typename\n }\n layout {\n omitFooter\n gridSpecs {\n Mobile {\n ...FacetV2LayoutGridFragment\n __typename\n }\n Phablet {\n ...FacetV2LayoutGridFragment\n __typename\n }\n Tablet {\n ...FacetV2LayoutGridFragment\n __typename\n }\n Desktop {\n ...FacetV2LayoutGridFragment\n __typename\n }\n WideScreen {\n ...FacetV2LayoutGridFragment\n __typename\n }\n UltraWideScreen {\n ...FacetV2LayoutGridFragment\n __typename\n }\n __typename\n }\n dlsPadding {\n top\n right\n bottom\n left\n __typename\n }\n __typename\n }\n custom\n logging\n __typename\n}\n\nfragment FacetV2ComponentFragment on FacetV2Component {\n id\n category\n __typename\n}\n\nfragment FacetV2TextFragment on FacetV2Text {\n title\n titleTextAttributes {\n textStyle\n textColor\n __typename\n }\n subtitle\n subtitleTextAttributes {\n textStyle\n textColor\n __typename\n }\n accessory\n accessoryTextAttributes {\n textStyle\n textColor\n __typename\n }\n description\n descriptionTextAttributes {\n textStyle\n textColor\n __typename\n }\n custom {\n key\n value\n __typename\n }\n __typename\n}\n\nfragment FacetV2ImageFragment on FacetV2Image {\n uri\n placeholder\n local\n style\n logging\n events {\n click {\n name\n data\n __typename\n }\n __typename\n }\n __typename\n}\n\nfragment FacetV2LayoutGridFragment on FacetV2LayoutGrid {\n interRowSpacing\n interColumnSpacing\n minDimensionCount\n __typename\n}\n\nfragment FacetV2PageFragment on FacetV2Page {\n next {\n name\n data\n __typename\n }\n onLoad {\n name\n data\n __typename\n }\n __typename\n}\n" } response = requests.post(url, headers=headers, json=payload) print(response.status_code) print(response.json())
内容的提问来源于stack exchange,提问作者Harsh Rao
相关产品推荐
相关产品推荐

