Вопрос или проблема
Для этого действительного URL:
https://open.spotify.com/oembed?url=https%3A%2F%2Fopen.spotify.com%2Fplaylist%2F37i9dQZF1DWTggY0yqBxES
Вызов метода GetAsync
у HttpClient завершается ошибкой 500.
Минимальная репродукция:
var client = new HttpClient();
var res = await client.GetAsync(
"https://open.spotify.com/oembed?url=https%3A%2F%2Fopen.spotify.com%2Fplaylist%2F37i9dQZF1DWTggY0yqBxES");
Console.WriteLine(res.StatusCode); // InternalServerError
Что на первый взгляд может заставить вас думать, что проблема на стороне Spotify. В конечном счете, именно сервер Spotify возвращает ошибку 500.
Однако каждый другой метод, который я пробовал для получения этого URL, работает без проблем
- попробуйте в браузере, это работает
- попробуйте с помощью curl, это работает:
curl "https://open.spotify.com/oembed?url=https%3A%2F%2Fopen.spotify.com%2Fplaylist%2F37i9dQZF1DWTggY0yqBxES"
- попробуйте с помощью javascript, это работает:
fetch("https://open.spotify.com/oembed?url=https%3A%2F%2Fopen.spotify.com%2Fplaylist%2F37i9dQZF1DWTggY0yqBxES")
.then(res => {
console.log(res)
})
- попробуйте в PowerShell, это работает:
Invoke-WebRequest "https://open.spotify.com/oembed?url=https%3A%2F%2Fopen.spotify.com%2Fplaylist%2F37i9dQZF1DWTggY0yqBxES"
Только в C# происходит сбой.
Что делает базовый запрос C# иначе, чем все эти другие методы?
HttpClient имеет разные заголовки по сравнению с другими. Например, заголовок User-Agent будет пустым, что может вызвать некоторые ошибки.
Оказалось, что проблема в том, что C# не добавляет заголовок user-agent по умолчанию.
Добавление:
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("smh");
решает проблему.
Если вы посмотрите на запрос в инструментах разработчика браузера и/или на скопированный запрос cURL, вы увидите множество установленных заголовков.
Сервер Spotify (и другие) ищет определенные заголовки для отправки ответа, поэтому вам также нужно установить эти заголовки в C# HttpClient
.
Посмотрите на следующий фрагмент кода, который успешно получает данные (так же, как и в браузере):
using var client = new HttpClient();
// Устанавливаем заголовки запроса
client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
client.DefaultRequestHeaders.Add("Accept-Language", "pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7");
client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
client.DefaultRequestHeaders.Add("Cookie", "sp_t=32d30582c0e595b1b03500e38cd7219b; _gcl_au=1.1.1632377271.1728126146; OptanonConsent=isGpcEnabled=0&datestamp=Sat+Oct+05+2024+13%3A02%3A29+GMT%2B0200+(czas+%C5%9Brodkowoeuropejski+letni)&version=202405.2.0&browserGpcFlag=0&isIABGlobal=false&hosts=&consentId=31c916af-3bbf-40c7-bf7c-a365cbc6aece&interactionCount=1&isAnonUser=1&landingPath=https%3A%2F%2Fopen.spotify.com%2F&groups=s00%3A1%2Cf00%3A0%2Cm00%3A0%2Ct00%3A0%2Cf11%3A0%2Ci00%3A0%2CV2STACK3%3A0%2CV2STACK11%3A0%2CV2STACK20%3A0%2Cm03%3A1; sp_landing=http%3A%2F%2Fopen.spotify.com%2Fapi%2Foembed%3Fsp_cid%3D32d30582c0e595b1b03500e38cd7219b%26device%3Ddesktop");
client.DefaultRequestHeaders.Add("Pragma", "no-cache");
client.DefaultRequestHeaders.Add("Priority", "u=0, i");
client.DefaultRequestHeaders.Add("sec-ch-ua", "\"Not)A;Brand\";v=\"99\", \"Opera\";v=\"113\", \"Chromium\";v=\"127\"");
client.DefaultRequestHeaders.Add("sec-ch-ua-mobile", "?0");
client.DefaultRequestHeaders.Add("sec-ch-ua-platform", "\"Windows\"");
client.DefaultRequestHeaders.Add("Sec-Fetch-Dest", "document");
client.DefaultRequestHeaders.Add("Sec-Fetch-Mode", "navigate");
client.DefaultRequestHeaders.Add("Sec-Fetch-Site", "none");
client.DefaultRequestHeaders.Add("Sec-Fetch-User", "?1");
client.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.120 Safari/537.36");
// Устанавливаем URL запроса
var url = "https://open.spotify.com/oembed?url=https%3A%2F%2Fopen.spotify.com%2Fplaylist%2F37i9dQZF1DWTggY0yqBxES";
// Выполняем GET запрос
var response = await client.GetAsync(url);
// Убедимся, что запрос был успешным
response.EnsureSuccessStatusCode();
// Читаем и отображаем содержимое ответа
var responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
Ответ или решение
Анализ проблемы с использованием HttpClient.GetAsync для конкретного URL
При работе с HTTP-запросами в приложениях на C# с использованием класса HttpClient
могут возникать ситуации, когда метод GetAsync
возвращает ошибку сервера, в частности код ошибки 500 (Internal Server Error). В данной статье мы рассмотрим конкретный случай с URL для получения оEmbed данных из Spotify, приведем возможные причины проблемы и предложим решения.
Описание проблемы
При выполнении следующего кода в C#:
var client = new HttpClient();
var res = await client.GetAsync("https://open.spotify.com/oembed?url=https%3A%2F%2Fopen.spotify.com%2Fplaylist%2F37i9dQZF1DWTggY0yqBxES");
Console.WriteLine(res.StatusCode); // InternalServerError
метод GetAsync
возвращает код состояния 500. Однако, данный URL успешно обрабатывается через браузер, cURL, JavaScript и PowerShell:
- Браузер: Открытие URL в браузере (например, Chrome или Firefox) возвращает ожидаемый результат.
- cURL: Используя команду
curl
, запрос выполняется без ошибок. - JavaScript: Метод
fetch()
успешно выполняется и возвращает данные. - PowerShell: Команда
Invoke-WebRequest
также работает корректно.
Причины возникновения ошибки
Причина, по которой запрос, выполненный с помощью HttpClient
, возвращает ошибку, заключается в следующем:
-
Отсутствие заголовков по умолчанию:
HttpClient
в C# не устанавливает некоторые заголовки, которые автоматически добавляются браузерами и другими инструментами. Одним из важнейших заголовков являетсяUser-Agent
. Этот заголовок может оказывать влияние на то, как сервер обрабатывает запрос. -
Требования к другим заголовкам: Spotify и другие серверы могут проверять наличие и соответствие определенных заголовков, таких как
Accept
,Accept-Language
, и других. При их отсутствии сервер может вернуть ошибку 500.
Решение проблемы
Для устранения ошибки 500 необходимо явно установить необходимые заголовки, которые обычно отправляются браузерами. Ключевое внимание стоит уделить заголовку User-Agent
, а также другим заголовкам, которые могут быть критичны для ответа сервера. Ниже приведен пример кода, который иллюстрирует это:
using var client = new HttpClient();
// Установите заголовки запроса
client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
client.DefaultRequestHeaders.Add("Accept-Language", "pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7");
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.120 Safari/537.36");
// Добавьте другие заголовки по аналогии, если это необходимо
// Установите URL запроса
var url = "https://open.spotify.com/oembed?url=https%3A%2F%2Fopen.spotify.com%2Fplaylist%2F37i9dQZF1DWTggY0yqBxES";
// Выполните GET-запрос
var response = await client.GetAsync(url);
// Убедитесь, что запрос выполнен успешно
response.EnsureSuccessStatusCode();
// Чтение и вывод содержания ответа
var responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
Заключение
В случае, если HttpClient.GetAsync
возвращает ошибку 500 для определенного URL, важно проверить, какие заголовки запрос отправляет. Установка не хватает заголовков, таких как User-Agent
, может стать решением проблемы. Обратите внимание, что разные серверы могут требовать разные заголовки, поэтому всегда полезно анализировать запросы в инструментах разработчика браузера, чтобы сделать запросы более „человечными“ и соответствовать требованиям сервера.