логотип PurpleSchool
логотип PurpleSchool

Использование React вместе с Go

Автор

Олег Марков

Введение

Связка React на фронтенде и Go на серверной стороне — частый выбор для создания современных веб-приложений. React обеспечивает быструю реакцию интерфейса, а Go — надёжный, быстрый и эффективный сервер. Такая архитектура идеально подходит для приложений с высокой нагрузкой и четким разделением клиентской и серверной логики.

В этой статье я расскажу, как организовать совместную работу React и Go. Вы увидите на примерах, как настроить такой проект, построить REST API на Go, собрать и раздавать фронтенд, а также обсудим обмен данными между клиентом и сервером. Мы разберём главные подходы, дадим советы по организации разработки и сходим по шагам к рабочей интеграции.

Архитектура взаимодействия React и Go

Перед тем, как писать код, важно понимать архитектурные аспекты:

  • React отвечает за отображение интерфейса и общается с сервером через HTTP/HTTPS (обычно с помощью fetch или axios).
  • Go реализует сервер, обрабатывающий запросы, отдающий данные (например, в формате JSON), выполняющий логику приложения и взаимодействующий с базой данных.

На диаграмме взаимодействие выглядит так:

  1. Браузер загружает собранный проект React.
  2. При необходимости данных React отправляет запросы к Go-серверу (обычно на endpoints REST API).
  3. Сервер Go возвращает ответ (например, JSON-данные), которые React отображает пользователю.

Это разделение облегчает масштабирование, тестирование и обновление частей приложения независимо друг от друга.

React и Go — это мощная комбинация для разработки современных веб-приложений. React отвечает за интерактивный пользовательский интерфейс, а Go обеспечивает высокую производительность и масштабируемость на стороне сервера. Если вы хотите узнать, как использовать React вместе с Go для создания быстрых и надежных приложений — приходите на наш большой курс Основы React, React Router и Redux Toolkit. На курсе 177 уроков и 17 упражнений, AI-тренажеры для безлимитной практики с кодом и задачами 24/7, решение задач с живым ревью наставника, еженедельные встречи с менторами.

Запуск проектов: структура и базовые настройки

Какой выбрать подход: монорепозиторий или разделение?

Вариант 1: Монорепозиторий

  • В корне находятся оба проекта (/frontend, /backend).
  • Используется единая система сборки (например, Makefile, docker-compose).
  • Упрощает настройку dev environment для команды.

Вариант 2: Отдельные репозитории

  • Фронтенд и бэкенд развиваются независимо.
  • Более чистое разделение разработки, лучше подходит для крупных команд.

Для примера ниже я буду использовать монорепозиторий — это удобно для старта и локальной разработки.

Пример структуры:

/myproject
  /frontend      // React-приложение
  /backend       // Go сервер
  README.md

Шаг 1. Создание React-приложения

Перейдите в каталог проекта и выполните:

npx create-react-app frontend

или если вы предпочитаете Vite:

npm create vite@latest frontend -- --template react

Это создаст папку frontend с типовой структурой React-приложения. Позже проект можно собрать через:

npm run build

Файлы сборки появляются в директории frontend/build или frontend/dist (зависит от инструмента).

Шаг 2. Создание Go-сервера

Давайте создадим каталог /backend с минимальным HTTP-сервером.

Пример простейшего сервера на Go:

// main.go
package main

import (
    "encoding/json"
    "log"
    "net/http"
)

// Item — пример структуры данных, которую сервер отдаёт клиенту
type Item struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

func main() {
    http.HandleFunc("/api/items", itemsHandler)

    // CORS middleware (для локальной разработки React сервера и Go)
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
    })

    log.Println("Server started at :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func itemsHandler(w http.ResponseWriter, r *http.Request) {
    // Создаем массив из двух элементов
    items := []Item{
        {ID: 1, Name: "Первый"},
        {ID: 2, Name: "Второй"},
    }
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(items)
}

Комментарии:

  • Сервер слушает порт 8080.
  • /api/items — endpoint, отдающий JSON-массив.
  • Добавлен заголовок Access-Control-Allow-Origin, чтобы не было ошибок CORS при запросах с локального React.

Такой сервер запускается командой:

go run main.go

Шаг 3. Общение между React и Go через REST API

Теперь давайте на стороне React запросим данные с Go-сервера и выведем их.

Пример компонента React для запроса API

import React, { useEffect, useState } from "react";

function ItemList() {
  const [items, setItems] = useState([]);

  useEffect(() => {
    // Запрашиваем данные у нашего Go API
    fetch("http://localhost:8080/api/items")
      .then((res) => res.json())
      .then((data) => setItems(data))
      .catch((err) => console.error("Ошибка запроса:", err));
  }, []);

  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

export default ItemList;

Пояснения:

  • Компонент при монтировании отправляет запрос к серверу Go.
  • Полученные данные показываются на странице.
  • Пока всё работает локально — React UI на 3000 порту, Go API на 8080. Для "production" есть другие подходы (см. ниже).

Решение проблемы CORS (кросс-доменные запросы)

Когда фронтенд и бэкенд работают на разных портах, браузер будет блокировать прямые запросы без соответствующих CORS-заголовков. Мы уже добавили их вручную выше, однако для больших проектов стоит использовать middleware.

Использование популярного пакета github.com/rs/cors:

// Добавьте импорт:
import "github.com/rs/cors"

// В main():
func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/api/items", itemsHandler)

    handler := cors.AllowAll().Handler(mux)

    log.Println("Server started at :8080")
    log.Fatal(http.ListenAndServe(":8080", handler))
}

Пояснения:

  • Теперь сервер корректно обрабатывает CORS, разрешая запросы с любого origin (для production стоит ограничить origin!).

Сборка фронтенда и раздача через Go

В продакшене удобно, чтобы бэкенд и фронтенд работали на одном адресе (домене и порте). Для этого Go-сервер можно научить раздавать статику — собранный React.

Как собрать React для продакшена:

cd frontend
npm run build

Выполняется сборка, в папке frontend/build появляются итоговые статические файлы.

Как добавить раздачу статики в Go

func main() {
    mux := http.NewServeMux()

    // API endpoint
    mux.HandleFunc("/api/items", itemsHandler)
    
    // Раздача статики
    fileServer := http.FileServer(http.Dir("../frontend/build"))
    mux.Handle("/", fileServer)

    log.Println("Server started at :8080")
    log.Fatal(http.ListenAndServe(":8080", mux))
}

Пояснения:

  • http.FileServer раздаёт все файлы из build React.
  • Теперь, если вместо API-запроса открыть браузером localhost:8080, загрузится собранная версия React-приложения.
  • Обратите внимание, что путь к папке сборки должен быть указан относительно текущего местоположения Go-сервера.

Работа с роутингом React (SPA и сервер)

При использовании client-side routing (например, с react-router), если пользователь обновит страницу по адресу вроде /profile, сервер попытается отдать файл или папку по этому пути, а не index.html — получите 404.

Решение: отдавать index.html на все не-API-запросы

Пример middleware для Go:

mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    // Если путь начинается с /api/ — пропускаем к API-обработчикам
    if strings.HasPrefix(r.URL.Path, "/api/") {
        mux.ServeHTTP(w, r)
        return
    }
    
    // Для остальных — отдаём index.html
    http.ServeFile(w, r, "../frontend/build/index.html")
}))

Пояснения:

  • Любой не-API-запрос приводит к отдаче index.html.
  • Это позволяет React с клиентским роутингом корректно работать при "рефреше".

Переменные окружения и настройка адресов

Когда разрабатываем React и Go раздельно, может возникнуть вопрос: "Куда слать запросы из React?"
В React используется переменная окружения, например:

В .env (в папке frontend):

REACT_APP_API_URL=http://localhost:8080/api

В коде:

fetch(`${process.env.REACT_APP_API_URL}/items`)
  .then(...)
// Или использовать axios с базовым URL

Пояснения:

  • Это упрощает переключение между production и development.

При сборке фронтенда и раздаче через Go всё работает на одном адресе, и использовать полный origin не нужно (достаточно относительных путей /api/items).

Советы по организации разработки

  • Для горячей перезагрузки и удобства локальной разработки используйте два процесса: отдельный сервер Go и отдельный dev-сервер React. Например:
    • cd backend && go run main.go
    • cd frontend && npm start
  • Используйте CORS только в development-режиме, в продакшн уберите Access-Control-Allow-Origin: *.
  • Для dev удобна настройка proxy на сервер фронтенда — чтобы не прописывать полный адрес API.

Пример настройки proxy в React

В frontend/package.json:

"proxy": "http://localhost:8080"

Пояснения:

  • Теперь fetch("/api/items") в React будет автоматически проксироваться на сервер Go.

Введение в разделение логики

React хранит только логику отображения (View), а вся бизнес-логика, доступ к БД или сторонним сервисам реализуется на стороне Go. Такой подход:

  • Упрощает понимание кода
  • Позволяет менять реализацию интерфейса без риска повредить серверную часть
  • Облегчает тестирование и масштабируемость

Как реализовать обработку POST-запросов и получение данных от клиента

Приведу пример простейшего POST-обработчика на Go, который примет данные из React.

Сервер Go:

func addItemHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "Метод не разрешён", http.StatusMethodNotAllowed)
        return
    }

    var item Item
    err := json.NewDecoder(r.Body).Decode(&item)
    if err != nil {
        http.Error(w, "Ошибка чтения body", http.StatusBadRequest)
        return
    }

    // Здесь можно записывать полученный item в БД...
    
    // Отправляем подтверждение клиенту
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(item)
}

// Добавьте обработчик в main():
mux.HandleFunc("/api/items", addItemHandler)

Запрос из React:

// Добавление элемента с помощью fetch
fetch("/api/items", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ id: 3, name: "Третий" })
})
.then(res => res.json())
.then(data => {
  // Действия после успешного добавления
});

Пояснения:

  • Всё строится на передаче JSON
  • В Go используем json.NewDecoder(r.Body).Decode(&item), чтобы распарсить тело запроса

Логика авторизации между React и Go

Часто в приложениях требуется авторизация пользователя (например, через токен JWT).

Краткая схема взаимодействия:

  1. React отправляет данные для входа на endpoint Go, например /api/login.
  2. Сервер проверяет пользователя и возвращает токен.
  3. React сохраняет токен (чаще всего в localStorage).
  4. При дальнейшем общении React включает токен в заголовок Authorization каждого запроса.

Пример fetch с токеном:

fetch("/api/items", {
  headers: {
    "Authorization": "Bearer " + token
  }
})

Пример проверки токена на Go

authHeader := r.Header.Get("Authorization")
// Проверить значение, выполнить валидацию токена

Пояснения:

  • Для реальной аутентификации применяйте библиотеки для работы с JWT.

Интеграция с Docker для единой разработки

Чтобы ваш проект легко запускался на любой машине, удобно упаковать frontend и backend в Docker-контейнеры.

Пример файла docker-compose.yml:

version: "3"
services:
  backend:
    build: ./backend
    ports:
      - "8080:8080"
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    environment:
      - REACT_APP_API_URL=http://backend:8080/api

Пояснения:

  • Теперь запуск с docker-compose up поднимет оба сервиса.
  • После сборки фронтенд может брать данные у бэкенда по внутренней сети Docker.

Заключение

React и Go — отличная пара для современных веб-приложений. React отвечает за удобный, быстрый пользовательский интерфейс, а Go обеспечивает эффективный серверный функционал. Связать их вместе легче всего через HTTP API, используя современные подходы: REST, CORS, удобную раздачу статики и разделение ответственности.

Применяйте предложенные шаги — настройте инфраструктуру, решите вопросы с CORS, проксированием и взаимодействием на уровне API. Благодаря этому ваш проект будет легко запускаться, масштабироваться, обновляться по частям без связывания компонентов излишне тесно.

Интеграция React и Go позволяет создавать мощные приложения. Для полноценной работы требуется умение управлять состоянием и роутингом. На курсе Основы React, React Router и Redux Toolkit вы получите необходимые знания. В первых 3 модулях уже доступно бесплатное содержание — начните погружаться в основы React уже сегодня.

Частозадаваемые технические вопросы и решения

Как настроить HTTPS (TLS) для сервера Go, чтобы React взаимодействовал безопасно?

Сгенерируйте самоподписанный сертификат или получите его через Let's Encrypt. В коде Go подключите сервер так: go log.Fatal(http.ListenAndServeTLS(":443", "cert.pem", "key.pem", mux)) А в fetch-запросах React используйте https:// адреса. Не забудьте разрешить запросы с нужного origin в CORS.

Как собрать фронтенд React и встроить его прямо в исполняемый файл Go?

Используйте пакеты типа github.com/jessevdk/go-assets или github.com/rakyll/statik, чтобы сгенерировать Go-код из папки build. После этого собранный бинарник Go раздает статику без внешних файлов.

Как ускорить сборку frontend и backend на CI/CD?

Для ускорения применяйте кэширование node_modules/nodemodules и go.mod/go.sum. В Docker используйте слои COPY или volumes, чтобы пересборка шла только при изменении файлов кода/зависимостей.

Как ограничить через CORS запросы только с фронтенда в production?

В middleware пакета github.com/rs/cors или вручную явно пропишите — w.Header().Set("Access-Control-Allow-Origin", "https://ваш-домен.ру").

Как проксировать все не-API-запросы на index.html для поддержки spa-роутинга?

В Go создайте middleware, который для всех путей, не начинающихся с /api/, отдаёт ../frontend/build/index.html. См. пример выше.

Стрелочка влевоИспользование Expo для разработки на ReactИнтеграция Express и ReactСтрелочка вправо

Постройте личный план изучения React до уровня Middle — бесплатно!

React — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по React

Открыть базу знаний

Лучшие курсы по теме

изображение курса

React и Redux Toolkit

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий