Олег Марков
Использование React вместе с Go
Введение
Связка React на фронтенде и Go на серверной стороне — частый выбор для создания современных веб-приложений. React обеспечивает быструю реакцию интерфейса, а Go — надёжный, быстрый и эффективный сервер. Такая архитектура идеально подходит для приложений с высокой нагрузкой и четким разделением клиентской и серверной логики.
В этой статье я расскажу, как организовать совместную работу React и Go. Вы увидите на примерах, как настроить такой проект, построить REST API на Go, собрать и раздавать фронтенд, а также обсудим обмен данными между клиентом и сервером. Мы разберём главные подходы, дадим советы по организации разработки и сходим по шагам к рабочей интеграции.
Архитектура взаимодействия React и Go
Перед тем, как писать код, важно понимать архитектурные аспекты:
- React отвечает за отображение интерфейса и общается с сервером через HTTP/HTTPS (обычно с помощью fetch или axios).
- Go реализует сервер, обрабатывающий запросы, отдающий данные (например, в формате JSON), выполняющий логику приложения и взаимодействующий с базой данных.
На диаграмме взаимодействие выглядит так:
- Браузер загружает собранный проект React.
- При необходимости данных React отправляет запросы к Go-серверу (обычно на endpoints REST API).
- Сервер 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).
Краткая схема взаимодействия:
- React отправляет данные для входа на endpoint Go, например
/api/login
. - Сервер проверяет пользователя и возвращает токен.
- React сохраняет токен (чаще всего в localStorage).
- При дальнейшем общении 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. См. пример выше.
Постройте личный план изучения React до уровня Middle — бесплатно!
React — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по React
Лучшие курсы по теме

React и Redux Toolkit
Антон Ларичев
TypeScript с нуля
Антон Ларичев