FedEx API 费率报价返回 404:“您请求的资源不再可用”

问题描述 投票:0回答:1

我正在尝试集成 FedEx API 以在我的 Node.js 应用程序中获取运费报价。我已按照文档进行操作,但始终收到 404 错误并显示以下消息:

“您请求的资源不再可用。”

FedEx API request failed with status: 404
- Response body: {"transactionId": "c2dda9ea-61fa-411a-9e39-e70239ee9370","errors":[{"code":"NOT.FOUND.ERROR","message":"The resource you requested is no longer available. Please modify your request and try again."}]}

我已根据 FedEx API 文档验证了端点 URL 和请求负载。这是我的 index.js 的相关部分:

const express = require('express');
const bodyParser = require('body-parser');
const fetch = require('node-fetch');
const path = require('path');

const app = express();
app.use(bodyParser.json());

const FEDEX_OAUTH_URL = 'https://apis.fedex.com/oauth/token';
const FEDEX_API_URL = 'https://apis.fedex.com/rate/v1/rates/quote';
const FEDEX_API_KEY = 'your_api_key';
const FEDEX_SECRET = 'your_api_secret';
const FEDEX_ACCOUNT_NUMBER = 'your_account_number';

async function getFedexToken() {
  const response = await fetch(FEDEX_OAUTH_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: FEDEX_API_KEY,
      client_secret: FEDEX_SECRET
    })
  });

  const responseBody = await response.text();
  if (!response.ok) {
    throw new Error(`Failed to get FedEx OAuth token: ${response.statusText}. Response Body: ${responseBody}`);
  }

  const data = JSON.parse(responseBody);
  return data.access_token;
}

app.post('/compare', async (req, res) => {
  const { originPostcode, originCountry, destinationPostcode, destinationCountry, weight } = req.body;

  const fedexRequest = {
    accountNumber: {
      value: FEDEX_ACCOUNT_NUMBER
    },
    requestedShipment: {
      shipper: {
        address: {
          postalCode: originPostcode,
          countryCode: originCountry.toUpperCase()
        }
      },
      recipient: {
        address: {
          postalCode: destinationPostcode,
          countryCode: destinationCountry.toUpperCase()
        }
      },
      shipDateStamp: new Date().toISOString().split('T')[0], // Today's date in YYYY-MM-DD format
      pickupType: 'DROPOFF_AT_FEDEX_LOCATION',
      serviceType: 'INTERNATIONAL_PRIORITY',
      rateRequestType: ['LIST', 'ACCOUNT'],
      customsClearanceDetail: {
        dutiesPayment: {
          paymentType: 'SENDER',
          payor: {
            responsibleParty: null
          }
        },
        commodities: [
          {
            description: 'Camera',
            quantity: 1,
            quantityUnits: 'PCS',
            weight: {
              units: 'KG',
              value: weight
            },
            customsValue: {
              amount: 100,
              currency: 'USD'
            }
          }
        ]
      },
      requestedPackageLineItems: [
        {
          weight: {
            units: 'KG',
            value: weight
          }
        }
      ]
    }
  };

  console.log('FedEx Request Payload:', JSON.stringify(fedexRequest, null, 2));

  try {
    const token = await getFedexToken();
    const response = await fetch(FEDEX_API_URL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-locale': 'en_US',
        'Authorization': `Bearer ${token}`
      },
      body: JSON.stringify(fedexRequest)
    });

    const responseBody = await response.text();
    if (!response.ok) {
      console.error('FedEx API request failed with status:', response.status);
      console.error('Response body:', responseBody); // Log the detailed error response
      throw new Error(`FedEx API request failed with status ${response.status}: ${responseBody}`);
    }

    const fedexData = JSON.parse(responseBody);
    console.log('FedEx Response Data:', JSON.stringify(fedexData, null, 2));

    if (!fedexData.output || !fedexData.output.rateReplyDetails) {
      throw new Error(`Unexpected FedEx API response structure: ${JSON.stringify(fedexData)}`);
    }

    const results = fedexData.output.rateReplyDetails.map(detail => ({
      courier: 'FedEx',
      cost: detail.ratedShipmentDetails[0].totalNetChargeWithDutiesAndTaxes.amount,
      service: detail.serviceType,
      transitTime: detail.commitDetails[0].commitTimestamp
    }));

    res.json({ results });
  } catch (error) {
    console.error('Error fetching data from FedEx API:', error);
    res.status(500).json({ error: error.message });
  }
});

app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, 'public', 'index.html'));
});

const PORT = process.env.PORT || 3001;

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
}).on('error', (err) => {
  if (err.code === 'EADDRINUSE') {
    console.error(`Port ${PORT} is already in use.`);
  } else {
    console.error(err);
  }
});

我原本希望收到 FedEx 提供的货件详细信息的费率报价,但我不断收到 404 错误。我已经验证了端点和请求负载结构,但我不确定是什么导致资源“不再可用”。

问题:

  • 获取报价的端点URL是否正确?
  • 有效负载结构是否满足 FedEx API 要求?
  • 是否有我可能遗漏的任何额外标头或参数?
javascript node.js json fedex
1个回答
0
投票

您在

s
之后错过了终点末尾的
quote
。完整网址是
https://apis.fedex.com/rate/v1/rates/quotes
而不是
https://apis.fedex.com/rate/v1/rates/quote

© www.soinside.com 2019 - 2024. All rights reserved.