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

在C#中通过REST API访问Amazon Alexa购物列表遇问题求助

问题描述

我想在C#中访问Alexa内部购物列表,用于搭建服务器内部同步工具。目前已查阅所有能找到的文档,但仍无法正常实现功能:

  • 现有代码可以获取access token,但调用https://api.amazonalexa.com/v2/householdlists/接口时返回500 Internal Server Error
  • 已经为自定义Alexa技能授予了所有列表权限

我需要解决两个核心问题:

  1. 如何从技能中获取所需的userId?
  2. 如何获取正确的授权令牌,让技能能返回所有购物列表?

目前找不到可用的最新示例,相关资料陈旧且零散。

现有代码如下:

获取Token的方法

private async Task<AlexaAuthResponse> GetAlexaToken()
{
    var endpointUri = "https://api.amazon.com/auth/o2/token";

    var nvc = new List<KeyValuePair<string, string>>();
    nvc.Add(new KeyValuePair<string, string>("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"));
    nvc.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
    nvc.Add(new KeyValuePair<string, string>("client_id", "amzn1.application-oa2-client.924096ecd9d542cdb5XXXXXXXXXXXXX"));
    nvc.Add(new KeyValuePair<string, string>("client_secret", "amzn1.oa2-cs.v1.15db95e13a90827b693510fbfa68f709f14b5a7285651d0eXXXXXXXXXXXXX"));
    nvc.Add(new KeyValuePair<string, string>("scope", "alexa:skill_messaging"));

    using var authRequest = new HttpRequestMessage(HttpMethod.Post, endpointUri);
    authRequest.Content = new FormUrlEncodedContent(nvc);
    var authResponse = await _httpClient.SendAsync(authRequest);

    using var graphResponseJson = JsonDocument.Parse(await authResponse.Content.ReadAsStreamAsync());
    var serializedJson = System.Text.Json.JsonSerializer.Serialize(graphResponseJson, new JsonSerializerOptions { WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping });

    return AlexaAuthResponse.GetSingleResultFromJson(serializedJson);
}

调用列表接口的方法

private async void button4_Click_1(object sender, EventArgs e)
{
    var auth = await GetAlexaToken();

    var apiUri = "https://api.amazonalexa.com/v2/householdlists/";

    using var graphRequest = new HttpRequestMessage(HttpMethod.Get, apiUri);
    graphRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", auth.access_token);
    graphRequest.Headers.TryAddWithoutValidation("Accept", "application/json;masked=false");
    var graphResponseMessage = await _httpClient.SendAsync(graphRequest);


    using var graphResponseJson = JsonDocument.Parse(await graphResponseMessage.Content.ReadAsStreamAsync());
    var serializedJson = System.Text.Json.JsonSerializer.Serialize(graphResponseJson, new JsonSerializerOptions { WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping });
}

解决方案

一、当前调用失败的核心原因

你用了client_credentials授权模式,且请求的scope是alexa:skill_messaging——这两个点完全不符合Alexa购物列表API的要求,导致获取的token没有访问列表数据的权限,进而触发服务器内部错误。

Alexa购物列表API要求使用Authorization Code Grant授权模式,且需要申请alexa::household_list相关的scope。

二、获取正确的授权令牌步骤

  1. 配置技能权限
    在Alexa开发者控制台,确保你的技能启用了Lists权限(包含读写购物/待办列表的权限),并在权限设置里勾选对应的选项。

  2. 使用Authorization Code模式获取Token
    这种模式需要用户先授权你的技能访问其列表数据,流程如下:

    • 构造授权URL引导用户访问:
      https://www.amazon.com/ap/oa?client_id=YOUR_CLIENT_ID&scope=alexa::household_list&response_type=code&redirect_uri=YOUR_REDIRECT_URI
      
      注意redirect_uri必须和你在Alexa控制台配置的一致。
    • 用户授权后,会跳转到你的redirect_uri并携带code参数。
    • 用这个code调用token接口换取令牌:
      private async Task<AlexaAuthResponse> GetTokenWithAuthCode(string authCode)
      {
          var endpointUri = "https://api.amazon.com/auth/o2/token";
          var nvc = new List<KeyValuePair<string, string>>
          {
              new("grant_type", "authorization_code"),
              new("client_id", "YOUR_CLIENT_ID"),
              new("client_secret", "YOUR_CLIENT_SECRET"),
              new("code", authCode),
              new("redirect_uri", "YOUR_REDIRECT_URI")
          };
      
          using var authRequest = new HttpRequestMessage(HttpMethod.Post, endpointUri);
          authRequest.Content = new FormUrlEncodedContent(nvc);
          var authResponse = await _httpClient.SendAsync(authRequest);
          authResponse.EnsureSuccessStatusCode();
      
          var responseContent = await authResponse.Content.ReadAsStringAsync();
          return JsonSerializer.Deserialize<AlexaAuthResponse>(responseContent);
      }
      
    • 拿到的token会包含access_token(有效期1小时)和refresh_token(长期有效,用于刷新token),这才是访问购物列表的有效凭证。

三、获取userId的两种方法

  1. 技能触发时提取:当用户通过语音触发你的Alexa技能时,技能请求上下文(SkillRequest)中的Context.System.User.UserId就是用户的唯一标识,可在技能处理逻辑中提取存储。
  2. 解析Token获取:access token是JWT格式,可直接解码读取user_id字段,示例代码:
    using System.IdentityModel.Tokens.Jwt;
    
    public string GetUserIdFromToken(string accessToken)
    {
        var handler = new JwtSecurityTokenHandler();
        var jwtToken = handler.ReadJwtToken(accessToken);
        return jwtToken.Claims.First(c => c.Type == "user_id").Value;
    }
    

四、修正后的列表接口调用

使用正确的token调用接口时,确保请求头配置正确:

private async Task<List<AlexaShoppingList>> GetShoppingLists(string accessToken)
{
    var apiUri = "https://api.amazonalexa.com/v2/householdlists/";
    using var request = new HttpRequestMessage(HttpMethod.Get, apiUri);
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
    request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    request.Headers.TryAddWithoutValidation("Accept-Language", "en-US"); // 根据需求调整语言

    var response = await _httpClient.SendAsync(request);
    response.EnsureSuccessStatusCode();

    var content = await response.Content.ReadAsStringAsync();
    return JsonSerializer.Deserialize<List<AlexaShoppingList>>(content);
}

注意事项

  • 私有技能需在开发者控制台添加测试用户,公开技能需通过Alexa审核,否则无法正常获取授权。
  • 存储refresh token时要加密,避免泄露用户数据。
  • access token过期后,用refresh token调用token接口获取新token,grant_type填refresh_token。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 23:10:23