You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hotelbeds ContentAPI调用失败问题排查求助

Hotelbeds测试API问题:ContentAPI无法正常工作,BookingAPI部分可用

刚注册了Hotelbeds的测试API,但ContentAPI请求无法正常工作(BookingAPI似乎可部分使用)。不确定是Hotelbeds端API密钥配置不当,还是本地配置有误。

相关API文档:

  • Hotelbeds Content API文档
  • Hotelbeds Booking API文档

根据文档,500内部服务器错误可能由系统错误或账户级配置错误导致,需联系apitude@hotelbeds.com排查。

已尝试操作

已在环境中配置API密钥与密钥,但测试结果如下:

Postman测试

以下请求返回500 Internal Server Error且无响应体:

{{endpoint}} = https://api.test.hotelbeds.com

{{endpoint}}/hotel-content-api/1.0/hotels?fields=all&language=ENG&from=1&to=100&useSecondaryLanguage=false

{{endpoint}}/hotel-content-api/1.0/locations/countries?fields=all&language=ENG&from=1&to=203

故意在APItude门户中写错API密钥后,请求返回401 Unauthorized:

401
Unauthorized
{
"error": "Request signature verification failed"
}
这表明认证流程正常。

BookingAPI测试结果不一:

  • {{endpoint}}/hotel-api/1.0/status 返回:
    { "auditData": { "timestamp": "2025-04-09 12:16:08.662" }, "status": "OK" }
    
  • {{endpoint}}/hotel-api/1.0/hotels 返回:
    { "auditData": 
      { 
        "processTime": "0", 
        "timestamp": "2025-04-09 12:15:29.702", 
        "requestHost": "10.214.136.70", 
        "serverId": "ip-10-214-129-132.eu-central-1.compute.internal#A+",
        "environment": "[awseucentral1, awseucentral1c, ip_10_214_129_132, eucentral1, secret]", 
        "release": "", 
        "token": "286B54DECE18475491F9AE9A12A801B9", 
        "internal": "0|||01|0|0||||||||||||0||1~1~1~0||0||0|dacab6e4d77041b4f6fbe3531c71dd93||||" 
      }, 
      "error": { 
        "code": "INVALID_DATA", 
        "message": "Error at property stay: Check-in must be in the future." 
      } 
    }
    

VS Code中Dart/Flutter测试

测试代码:

// lib/features/api/presentation/pages/content_api_test_page.dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart';

/// A test page for verifying HotelBeds Content API integration.
/// This page sends a GET request to the Content API endpoint and displays the result.
///
/// This file is part of the **API presentation** layer. In a clean architecture,
/// the API integration logic belongs in the **infrastructure** layer (e.g. in service classes),
/// while this page lives in the presentation layer. Separating these concerns helps with
/// maintainability and makes it easier to replace the API later if needed.
class ContentApiTestPage extends StatefulWidget {
  const ContentApiTestPage({super.key});

  @override
  State<ContentApiTestPage> createState() => _ContentApiTestPageState();
}

class _ContentApiTestPageState extends State<ContentApiTestPage> {
  String? _responseText;
  bool _isLoading = false;

  // Replace these with your actual test API key and API secret from HotelBeds.
  final String _apiKey = (API_key_here);
  final String _apiSecret = (API_secret_here);

  // Generates a SHA256 X-Signature by concatenating the API key, secret, and current timestamp (in seconds).
  String generateSignature() {
    final timestamp =
        (DateTime.now().millisecondsSinceEpoch / 1000).round().toString();
    final stringToSign = '$_apiKey$_apiSecret$timestamp';
    final bytes = utf8.encode(stringToSign);
    final digest = sha256.convert(bytes);
    return digest.toString();
  }

  // Sends an HTTP GET request to the Content API endpoint, using the proper headers.
  // Prints and displays the JSON response.
  Future<void> fetchContentData() async {
    setState(() {
      _isLoading = true;
      _responseText = null;
    });

    // Build the URI for the Content API endpoint.
    // Here we use the "hotels" endpoint from the HotelBeds Content API.
    final uri =
        Uri.parse("https://api.test.hotelbeds.com/content-api/1.0/hotels");

    // Create headers including Api-key and X-Signature.
    final headers = {
      'Accept': 'application/json',
      'Api-key': _apiKey,
      'X-Signature': generateSignature(),
    };

    try {
      final response = await http.get(uri, headers: headers);
      if (response.statusCode == 200) {
        setState(() {
          _responseText = response.body;
        });
        print("Content API Response: ${response.body}");
      } else {
        setState(() {
          _responseText =
              "Error: ${response.statusCode} ${response.reasonPhrase}";
        });
        print(
            "Error fetching content: ${response.statusCode} ${response.reasonPhrase}");
      }
    } catch (e) {
      setState(() {
        _responseText = "Error: $e";
      });
      print("Exception during fetching content: $e");
    }
    setState(() {
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Content API Test")),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // A button to trigger the API call.
            ElevatedButton(
              onPressed: fetchContentData,
              child: const Text("Fetch Content Data"),
            ),
            const SizedBox(height: 16),
            // Show loading indicator while fetching.
            if (_isLoading) const Center(child: CircularProgressIndicator()),
            // Display the API response text (or error message) in a scrollable area.
            if (_responseText != null)
              Expanded(
                  child: SingleChildScrollView(child: Text(_responseText!))),
          ],
        ),
      ),
    );
  }
}

当URI为ContentAPI地址时,返回:

flutter: Error fetching content: 404 Not Found

当URI为BookingAPI的status地址时,返回:

flutter: Content API Response: {"auditData":{"timestamp":"2025-04-10 02:59:55.077"},"status":"OK"}

内容的提问来源于stack exchange,提问作者William Chen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 12:31:02