← Назад к вопросам
На какие два потока прокси сервер разделяет запрос?
1.8 Middle🔥 141 комментариев
#DevOps и инфраструктура#Асинхронность и многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Краткий ответ
Прокси сервер разделяет обработку запроса на два основных потока (или задачи):
- Входящий поток (Inbound) - обработка запроса от клиента
- Исходящий поток (Outbound) - отправка запроса на целевой сервер и получение ответа
Детальное объяснение
Поток 1: Входящий (Inbound) - от клиента к прокси
Этот поток отвечает за:
- Приём HTTP запроса от клиента
- Парсинг заголовков и тела запроса
- Валидация запроса
- Применение входящих правил (filtering, rate limiting, authentication)
- Буферизация данных запроса если необходимо
- Трансформация запроса (изменение заголовков, URL переписывание)
import asyncio
from aiohttp import web
class ProxyServer:
async def handle_inbound(self, request):
# Поток 1: Входящий
print(f'Received request: {request.method} {request.path}')
print(f'Headers: {dict(request.headers)}')
# Валидация и обработка входящего запроса
if not self.is_valid_request(request):
return web.Response(status=400, text='Invalid request')
# Преобразование запроса если нужно
modified_request = self.transform_request(request)
return modified_request
Поток 2: Исходящий (Outbound) - от прокси к целевому серверу
Этот поток отвечает за:
- Отправку модифицированного запроса на целевой сервер
- Получение ответа от целевого сервера
- Обработка ошибок соединения (retry, timeout)
- Кэширование ответа если нужно
- Применение исходящих правил (compression, response modification)
- Отправку ответа обратно клиенту
import aiohttp
import asyncio
class ProxyServer:
async def handle_outbound(self, request, target_url):
# Поток 2: Исходящий
try:
async with aiohttp.ClientSession() as session:
# Отправляем запрос на целевой сервер
async with session.request(
method=request.method,
url=target_url,
headers=request.headers,
data=await request.read(),
timeout=aiohttp.ClientTimeout(total=30)
) as response:
# Получаем ответ
response_data = await response.read()
# Применяем исходящие правила
modified_response = self.transform_response(
response.status,
response.headers,
response_data
)
return modified_response
except asyncio.TimeoutError:
return web.Response(status=504, text='Gateway Timeout')
except aiohttp.ClientError as e:
return web.Response(status=502, text=f'Bad Gateway: {e}')
Полный пример асинхронного прокси
import aiohttp
from aiohttp import web
import asyncio
from typing import Tuple
class AsyncProxy:
def __init__(self, target_base_url: str):
self.target_base_url = target_base_url
async def handle_request(self, request: web.Request) -> web.StreamResponse:
"""
Главный обработчик который координирует оба потока
"""
# Поток 1: Входящий (Inbound)
inbound_result = await self._handle_inbound(request)
if isinstance(inbound_result, web.Response):
return inbound_result # Ошибка валидации
modified_request = inbound_result
# Поток 2: Исходящий (Outbound)
return await self._handle_outbound(modified_request, request)
async def _handle_inbound(self, request: web.Request):
"""
Поток 1: Входящий - обработка от клиента
"""
print(f'[INBOUND] {request.method} {request.path}')
# Валидация
if len(request.path) > 2000:
return web.Response(status=414, text='URI Too Long')
# Rate limiting (пример)
if not self._check_rate_limit(request.remote):
return web.Response(status=429, text='Too Many Requests')
# Логирование
print(f'[INBOUND] Headers: {dict(request.headers)}')
# Готовим данные для исходящего потока
inbound_data = {
'method': request.method,
'path': request.path,
'query': request.query_string,
'headers': dict(request.headers),
'body': await request.read()
}
return inbound_data
async def _handle_outbound(self, inbound_data: dict,
original_request: web.Request) -> web.StreamResponse:
"""
Поток 2: Исходящий - отправка на целевой сервер
"""
target_url = f"{self.target_base_url}{inbound_data['path']}"
if inbound_data['query']:
target_url += f"?{inbound_data['query']}"
print(f'[OUTBOUND] Forwarding to {target_url}')
try:
async with aiohttp.ClientSession() as session:
# Отправляем на целевой сервер
async with session.request(
method=inbound_data['method'],
url=target_url,
headers=inbound_data['headers'],
data=inbound_data['body'],
timeout=aiohttp.ClientTimeout(total=30),
ssl=False # Для самоподписанных сертификатов
) as response:
print(f'[OUTBOUND] Response status: {response.status}')
# Читаем ответ
response_body = await response.read()
# Создаём ответ для клиента
return web.Response(
status=response.status,
body=response_body,
headers=response.headers,
content_type=response.content_type
)
except asyncio.TimeoutError:
print('[OUTBOUND] Timeout connecting to target')
return web.Response(status=504, text='Gateway Timeout')
except aiohttp.ClientConnectorError as e:
print(f'[OUTBOUND] Connection error: {e}')
return web.Response(status=502, text='Bad Gateway')
def _check_rate_limit(self, client_ip: str) -> bool:
# Простая реализация rate limiting
return True
# Запуск
if __name__ == '__main__':
app = web.Application()
proxy = AsyncProxy('http://example.com')
app.router.add_route('*', '/{path_info:.*}', proxy.handle_request)
web.run_app(app, host='127.0.0.1', port=8080)
Синхронный пример (с использованием threading)
import requests
from flask import Flask, request, Response
import threading
app = Flask(__name__)
TARGET_URL = 'http://example.com'
@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT', 'DELETE'])
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def proxy(path):
# Поток 1: Входящий (Inbound)
def handle_inbound():
print(f'[INBOUND] {request.method} {request.path}')
return {
'method': request.method,
'path': path,
'headers': dict(request.headers),
'data': request.get_data()
}
# Поток 2: Исходящий (Outbound)
def handle_outbound(inbound_data):
url = f"{TARGET_URL}/{inbound_data['path']}"
print(f'[OUTBOUND] Forwarding to {url}')
try:
response = requests.request(
method=inbound_data['method'],
url=url,
headers=inbound_data['headers'],
data=inbound_data['data'],
timeout=30,
allow_redirects=True
)
return Response(
response.content,
status=response.status_code,
headers=dict(response.headers)
)
except requests.Timeout:
return Response('Gateway Timeout', status=504)
except requests.RequestException as e:
return Response(f'Bad Gateway: {e}', status=502)
inbound_data = handle_inbound()
return handle_outbound(inbound_data)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8080)
Ключевые различия между потоками
| Характеристика | Входящий (Inbound) | Исходящий (Outbound) |
|---|---|---|
| Источник | Клиент | Прокси сервер |
| Назначение | Прокси сервер | Целевой сервер |
| Задачи | Валидация, трансформация | Отправка, получение, кэширование |
| Направление | Клиент → Прокси | Прокси → Сервер |
| Обработка ошибок | 4xx ошибки | 5xx ошибки |
Практическое применение
Этот паттерн используется в:
- nginx/Apache - веб прокси
- API Gateway - API прокси
- Load Balancer - распределение нагрузки
- Reverse Proxy - кэширование и ускорение
- VPN/HTTP Proxy - анонимизация
Вывод: Прокси сервер разделяет обработку на входящий поток (от клиента) и исходящий поток (к целевому серверу), что позволяет независимо обрабатывать, трансформировать и оптимизировать каждую сторону соединения.