HttpClient.GetAsync не работает для конкретного URL

Вопрос или проблема

Для этого действительного 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, возвращает ошибку, заключается в следующем:

  1. Отсутствие заголовков по умолчанию: HttpClient в C# не устанавливает некоторые заголовки, которые автоматически добавляются браузерами и другими инструментами. Одним из важнейших заголовков является User-Agent. Этот заголовок может оказывать влияние на то, как сервер обрабатывает запрос.

  2. Требования к другим заголовкам: 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, может стать решением проблемы. Обратите внимание, что разные серверы могут требовать разные заголовки, поэтому всегда полезно анализировать запросы в инструментах разработчика браузера, чтобы сделать запросы более „человечными“ и соответствовать требованиям сервера.

Оцените материал
Добавить комментарий

Капча загружается...