> Как программа определяет URL для выполнения запросов по списку (Go)
Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы
Компании: Ozon
Стек: Go
> Пример ответа
Короткий ответ
Программа определяет URL для запросов через конфигурацию (env vars, config file), service discovery или DNS. В Go обычно используется net/http с базовым URL из конфига, а пути формируются через fmt.Sprintf или url.URL из стандартной библиотеки. Для списка URL применяется массив строк из конфига или отдельный сервис реестра. Ключевой момент - не хардкодить URL, а выносить их в настройки и обрабатывать ошибки при парсинге.
Подробное объяснение
В Go URL для запросов определяется на нескольких уровнях:
-
Конфигурация - через
os.Getenv,flag, или файлы (JSON, YAML, env). Для списка URL обычно используется JSON-массив или строка с разделителями. -
Формирование URL - базовый URL из конфига, путь и query-параметры собираются через
net/url:url.Parseдля разбораurl.URLструктура для модификации полейQuery()для параметров
-
Service discovery - для динамических списков (Kubernetes, Consul) URL получают через API или DNS SRV-записи.
-
Балансировка - если список URL, выбор может быть round-robin, random или по health-check.
Пример структуры конфига:
GOtype Config struct {Endpoints []string `json:"endpoints"`Timeout time.Duration}
На практике
Для списка URL в Go-сервисе:
- Используйте
[]stringв конфиге, но валидируйте каждый URL черезurl.ParseRequestURI. - Для production - разделяйте базовый URL и пути, чтобы не дублировать.
- При работе с несколькими сервисами - применяйте интерфейс с методом
BaseURL(), а не глобальные переменные. - Для динамического списка - обновляйте конфиг через сигналы (SIGHUP) или watch на файл.
- Не забывайте про контекст и таймауты - URL может быть недоступен.
Пример кода
GOpackage mainimport ("context""fmt""net/http""net/url""os""time")type Client struct {baseURL *url.URLendpoints []stringhttp *http.Client}func NewClient(endpoints []string) (*Client, error) {if len(endpoints) == 0 {return nil, fmt.Errorf("no endpoints provided")}base, err := url.Parse(endpoints[0])if err != nil {return nil, fmt.Errorf("invalid base URL: %w", err)}return &Client{baseURL: base,endpoints: endpoints,http: &http.Client{Timeout: 5 * time.Second},}, nil}func (c *Client) BuildURL(path string, params url.Values) string {u := *c.baseURLu.Path = pathu.RawQuery = params.Encode()return u.String()}func (c *Client) Fetch(ctx context.Context, path string) (*http.Response, error) {req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.BuildURL(path, nil), nil)if err != nil {return nil, err}return c.http.Do(req)}func main() {// из env: ENDPOINTS="http://a.com,http://b.com"raw := os.Getenv("ENDPOINTS")endpoints := splitAndTrim(raw)client, err := NewClient(endpoints)if err != nil {panic(err)}resp, err := client.Fetch(context.Background(), "/api/v1/items")if err != nil {fmt.Println("error:", err)return}defer resp.Body.Close()fmt.Println("status:", resp.StatusCode)}func splitAndTrim(s string) []string {if s == "" {return nil}parts := strings.Split(s, ",")result := make([]string, 0, len(parts))for _, p := range parts {if trimmed := strings.TrimSpace(p); trimmed != "" {result = append(result, trimmed)}}return result}
Как отвечать на собеседовании
- Начните с конфигурации - это ожидаемый ответ для senior.
- Упомяните разницу между статическим и динамическим списком URL.
- Покажите понимание
net/url- это важный нюанс Go. - Расскажите про обработку ошибок: невалидный URL, пустой список, таймауты.
- Если спросят про production - скажите про service discovery и health checks.
- Не углубляйтесь в детали фреймворков, если не спросят.
Что проверяет интервьюер
- Понимание разделения конфигурации и кода.
- Умение работать с
net/urlиnet/httpв Go. - Навыки обработки ошибок и edge cases.
- Знание паттернов для динамических списков (service discovery).
- Умение проектировать API клиента (интерфейсы, зависимости).
Типичные ошибки
- Хардкод URL в коде - сразу красный флаг.
- Игнорирование ошибок при парсинге URL -
url.Parseможет вернуть ошибку. - Не учитывать trailing slash -
http://a.com/apivshttp://a.com/api/. - Путать base URL и полный URL - при изменении хоста ломается всё.
- Не использовать
contextдля отмены запросов. - Забывать про валидацию пустого списка endpoints.
- Складывать URL через конкатенацию строк вместо
url.URL.
> Похожие задачи по Go
Какой индекс построить для запроса с условиями на несколько столбцов
Как понять, что код отработал правильно
Как называются ресиверы в Go и когда использовать ресивер по значению или по указателю
Используете ли вы пакет sync.Pool для контроля памяти в Go
> Похожие задачи по backend
Какой индекс построить для запроса с условиями на несколько столбцов
Как понять, что код отработал правильно
Как называются ресиверы в Go и когда использовать ресивер по значению или по указателю
Используете ли вы пакет sync.Pool для контроля памяти в Go
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью