在C#中通过REST API访问Amazon Alexa购物列表遇问题求助
问题描述
我想在C#中访问Alexa内部购物列表,用于搭建服务器内部同步工具。目前已查阅所有能找到的文档,但仍无法正常实现功能:
- 现有代码可以获取access token,但调用
https://api.amazonalexa.com/v2/householdlists/接口时返回500 Internal Server Error - 已经为自定义Alexa技能授予了所有列表权限
我需要解决两个核心问题:
- 如何从技能中获取所需的userId?
- 如何获取正确的授权令牌,让技能能返回所有购物列表?
目前找不到可用的最新示例,相关资料陈旧且零散。
现有代码如下:
获取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。
二、获取正确的授权令牌步骤
配置技能权限
在Alexa开发者控制台,确保你的技能启用了Lists权限(包含读写购物/待办列表的权限),并在权限设置里勾选对应的选项。使用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_URIredirect_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),这才是访问购物列表的有效凭证。
- 构造授权URL引导用户访问:
三、获取userId的两种方法
- 技能触发时提取:当用户通过语音触发你的Alexa技能时,技能请求上下文(
SkillRequest)中的Context.System.User.UserId就是用户的唯一标识,可在技能处理逻辑中提取存储。 - 解析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
相关产品推荐
相关产品推荐

