我试图通过opensea的graphql api使用request-promise检索一个集合。我发送带有这些参数的请求,作为响应,我一直收到状态码 403。我直接从浏览器复制了参数,在该浏览器中使用 fetch 可以正常工作。
const options = {
method: 'POST',
url: 'https://api.opensea.io/graphql',
headers: {
Host: 'api.opensea.io',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
'content-type': 'application/json',
accept: '*/*',
origin: 'https://opensea.io',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'https://opensea.io/'
},
body: {
id: 'collectionQuery',
query: 'query collectionQuery(\n $collection: CollectionSlug!\n $collections: [CollectionSlug!]\n $collectionQuery: String\n $includeHiddenCollections: Boolean\n $numericTraits: [TraitRangeType!]\n $query: String\n $sortAscending: Boolean\n $sortBy: SearchSortBy\n $stringTraits: [TraitInputType!]\n $toggles: [SearchToggle!]\n $showContextMenu: Boolean\n) {\n collection(collection: $collection) {\n isEditable\n bannerImageUrl\n name\n description\n imageUrl\n relayId\n representativeAsset {\n assetContract {\n openseaVersion\n id\n }\n id\n }\n ...collection_url\n ...CollectionHeader_data\n id\n }\n assets: query {\n ...AssetSearch_data_1bS60n\n }\n}\n\nfragment AssetCardContent_asset on AssetType {\n relayId\n name\n ...AssetMedia_asset\n assetContract {\n address\n chain\n openseaVersion\n id\n }\n tokenId\n collection {\n slug\n id\n }\n isDelisted\n}\n\nfragment AssetCardContent_assetBundle on AssetBundleType {\n assetQuantities(first: 18) {\n edges {\n node {\n asset {\n relayId\n ...AssetMedia_asset\n id\n }\n id\n }\n }\n }\n}\n\nfragment AssetCardFooter_assetBundle on AssetBundleType {\n name\n assetCount\n assetQuantities(first: 18) {\n edges {\n node {\n asset {\n collection {\n name\n relayId\n isVerified\n ...collection_url\n id\n }\n id\n }\n id\n }\n }\n }\n assetEventData {\n lastSale {\n unitPriceQuantity {\n ...AssetQuantity_data\n id\n }\n }\n }\n orderData {\n bestBid {\n orderType\n paymentAssetQuantity {\n ...AssetQuantity_data\n id\n }\n }\n bestAsk {\n closedAt\n orderType\n dutchAuctionFinalPrice\n openedAt\n priceFnEndedAt\n quantity\n decimals\n paymentAssetQuantity {\n quantity\n ...AssetQuantity_data\n id\n }\n }\n }\n}\n\nfragment AssetCardFooter_asset_2V84VL on AssetType {\n name\n tokenId\n collection {\n name\n isVerified\n ...collection_url\n id\n }\n hasUnlockableContent\n isDelisted\n isFrozen\n assetContract {\n address\n chain\n openseaVersion\n id\n }\n assetEventData {\n firstTransfer {\n timestamp\n }\n lastSale {\n unitPriceQuantity {\n ...AssetQuantity_data\n id\n }\n }\n }\n decimals\n orderData {\n bestBid {\n orderType\n paymentAssetQuantity {\n ...AssetQuantity_data\n id\n }\n }\n bestAsk {\n closedAt\n orderType\n dutchAuctionFinalPrice\n openedAt\n priceFnEndedAt\n quantity\n decimals\n paymentAssetQuantity {\n quantity\n ...AssetQuantity_data\n id\n }\n }\n }\n}\n\nfragment AssetCardHeader_data_27d9G3 on AssetType {\n relayId\n favoritesCount\n isDelisted\n isFavorite\n ...AssetContextMenu_data_3z4lq0 @include(if: $showContextMenu)\n}\n\nfragment AssetContextMenu_data_3z4lq0 on AssetType {\n ...asset_edit_url\n ...asset_url\n ...itemEvents_data\n isDelisted\n isEditable {\n value\n reason\n }\n isListable\n ownership(identity: {}) {\n isPrivate\n quantity\n }\n creator {\n address\n id\n }\n collection {\n isAuthorizedEditor\n id\n }\n}\n\nfragment AssetMedia_asset on AssetType {\n animationUrl\n backgroundColor\n collection {\n displayData {\n cardDisplayStyle\n }\n id\n }\n isDelisted\n displayImageUrl\n}\n\nfragment AssetQuantity_data on AssetQuantityType {\n asset {\n ...Price_data\n id\n }\n quantity\n}\n\nfragment AssetSearchFilter_data_1GloFv on Query {\n ...CollectionFilter_data_tXjHb\n collection(collection: $collection) {\n numericTraits {\n key\n value {\n max\n min\n }\n ...NumericTraitFilter_data\n }\n stringTraits {\n key\n ...StringTraitFilter_data\n }\n id\n }\n ...PaymentFilter_data_2YoIWt\n}\n\nfragment AssetSearchList_data_gVyhu on SearchResultType {\n asset {\n assetContract {\n address\n chain\n id\n }\n collection {\n isVerified\n id\n }\n relayId\n tokenId\n ...AssetSelectionItem_data\n ...asset_url\n id\n }\n assetBundle {\n relayId\n id\n }\n ...Asset_data_gVyhu\n}\n\nfragment AssetSearch_data_1bS60n on Query {\n ...CollectionHeadMetadata_data_2YoIWt\n ...AssetSearchFilter_data_1GloFv\n ...SearchPills_data_2Kg4Sq\n search(collections: $collections, first: 32, numericTraits: $numericTraits, querystring: $query, resultType: ASSETS, sortAscending: $sortAscending, sortBy: $sortBy, stringTraits: $stringTraits, toggles: $toggles) {\n edges {\n node {\n ...AssetSearchList_data_gVyhu\n __typename\n }\n cursor\n }\n totalCount\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment AssetSelectionItem_data on AssetType {\n backgroundColor\n collection {\n displayData {\n cardDisplayStyle\n }\n imageUrl\n id\n }\n imageUrl\n name\n relayId\n}\n\nfragment Asset_data_gVyhu on SearchResultType {\n asset {\n isDelisted\n ...AssetCardHeader_data_27d9G3\n ...AssetCardContent_asset\n ...AssetCardFooter_asset_2V84VL\n ...AssetMedia_asset\n ...asset_url\n ...itemEvents_data\n id\n }\n assetBundle {\n ...bundle_url\n ...AssetCardContent_assetBundle\n ...AssetCardFooter_assetBundle\n id\n }\n}\n\nfragment CollectionFilter_data_tXjHb on Query {\n selectedCollections: collections(first: 25, collections: $collections, includeHidden: true) {\n edges {\n node {\n assetCount\n imageUrl\n name\n slug\n isVerified\n id\n }\n }\n }\n collections(first: 100, includeHidden: $includeHiddenCollections, query: $collectionQuery, sortBy: SEVEN_DAY_VOLUME) {\n edges {\n node {\n assetCount\n imageUrl\n name\n slug\n isVerified\n id\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment CollectionHeadMetadata_data_2YoIWt on Query {\n collection(collection: $collection) {\n bannerImageUrl\n description\n imageUrl\n name\n id\n }\n}\n\nfragment CollectionHeader_data on CollectionType {\n name\n description\n imageUrl\n bannerImageUrl\n ...CollectionStatsBar_data\n ...SocialBar_data\n ...verification_data\n}\n\nfragment CollectionModalContent_data on CollectionType {\n description\n imageUrl\n name\n slug\n}\n\nfragment CollectionStatsBar_data on CollectionType {\n stats {\n numOwners\n totalSupply\n totalVolume\n id\n }\n slug\n floorPrice\n}\n\nfragment NumericTraitFilter_data on NumericTraitTypePair {\n key\n value {\n max\n min\n }\n}\n\nfragment PaymentFilter_data_2YoIWt on Query {\n paymentAssets(first: 10) {\n edges {\n node {\n symbol\n relayId\n id\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n PaymentFilter_collection: collection(collection: $collection) {\n paymentAssets {\n symbol\n relayId\n id\n }\n id\n }\n}\n\nfragment Price_data on AssetType {\n decimals\n imageUrl\n symbol\n usdSpotPrice\n assetContract {\n blockExplorerLink\n chain\n id\n }\n}\n\nfragment SearchPills_data_2Kg4Sq on Query {\n selectedCollections: collections(first: 25, collections: $collections, includeHidden: true) {\n edges {\n node {\n imageUrl\n name\n slug\n ...CollectionModalContent_data\n id\n }\n }\n }\n}\n\nfragment SocialBar_data on CollectionType {\n relayId\n discordUrl\n externalUrl\n instagramUsername\n mediumUsername\n slug\n telegramUrl\n twitterUsername\n ...collection_url\n}\n\nfragment StringTraitFilter_data on StringTraitType {\n counts {\n count\n value\n }\n key\n}\n\nfragment asset_edit_url on AssetType {\n assetContract {\n address\n chain\n id\n }\n tokenId\n collection {\n slug\n id\n }\n}\n\nfragment asset_url on AssetType {\n assetContract {\n address\n chain\n id\n }\n tokenId\n}\n\nfragment bundle_url on AssetBundleType {\n slug\n}\n\nfragment collection_url on CollectionType {\n slug\n}\n\nfragment itemEvents_data on AssetType {\n assetContract {\n address\n chain\n id\n }\n tokenId\n}\n\nfragment verification_data on CollectionType {\n isMintable\n isSafelisted\n isVerified\n}\n',
variables: {
collection: 'beeple-special-edition',
collections: ['beeple-special-edition'],
collectionQuery: null,
includeHiddenCollections: null,
numericTraits: null,
query: null,
sortAscending: true,
sortBy: 'PRICE',
stringTraits: null,
toggles: null,
showContextMenu: true
}
}
这会导致响应状态代码 403 并在响应正文中显示error code: 1020