当前位置: 代码网 > 服务器>服务器>Linux > Nginx解决前后端分离架构下的Session共享的几种方法

Nginx解决前后端分离架构下的Session共享的几种方法

2026年04月20日 Linux 我要评论
前后端分离的 session 困境传统单体架构:用户 → nginx → tomcat/php ↓ session 存储在内存(单机无问题)前后端分离

前后端分离的 session 困境

传统单体架构:
用户 → nginx → tomcat/php
              ↓
           session 存储在内存(单机无问题)

前后端分离架构:
用户 → nginx → 前端服务器 (vue/react 静态资源)
              ↓
            api 网关 → 后端服务集群 (tomcat-a, tomcat-b, tomcat-c)
                          ↓
                    session 存储在各自内存(用户请求被负载到不同节点,session 丢失!)

核心问题:负载均衡后,同一用户的请求可能落到不同后端节点,导致 session 不一致。

方案一:nginx 粘性会话(sticky session)

让同一用户的请求始终落到同一后端节点。

1. 基于 ip hash(简单但粗糙)

upstream backend {
    # 根据客户端 ip 的 hash 值分配后端
    ip_hash;
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}
server {
    listen 80;
    server_name api.example.com;
    location /api/ {
        proxy_pass http://backend;
        proxy_set_header host $host;
        proxy_set_header x-real-ip $remote_addr;
    }
}

缺点

  • 用户 ip 变化(移动网络、代理)会切换节点
  • 某节点故障时,该节点用户 session 丢失
  • 无法动态扩容(增减节点导致 hash 重新计算)

2. 基于 cookie 的粘性会话(推荐)

使用 sticky 模块或第三方模块:

# 需要编译安装 nginx-sticky-module
upstream backend {
    sticky cookie srv_id expires=1h domain=.example.com path=/;
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}
server {
    location /api/ {
        proxy_pass http://backend;
    }
}

原理:nginx 设置 cookie srv_id=后端标识,后续请求根据 cookie 值路由。

方案二:session 集中存储(推荐)

将 session 从应用内存剥离,存储到共享中间件。

架构图

用户请求 → nginx → 后端服务a
              ↓       ↓
              ↓    读写 session
              ↓       ↓
            redis/mysql(session 存储中心)
              ↑       ↑
              ↑    读写 session
              ↑       ↓
            后端服务b(获取同一 session)

1. spring boot + redis 配置示例

// application.yml
spring:
  session:
    store-type: redis
    redis:
      namespace: myapp:session
      flush-mode: on_save
      cleanup-cron: 0 */30 * * * *
  redis:
    host: 192.168.1.50
    port: 6379
    password: secret
    timeout: 2000ms
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
server:
  servlet:
    session:
      timeout: 30m  # session 过期时间

2. nginx 负载均衡配置(无状态)

upstream backend {
    # 无需 ip_hash,纯轮询即可
    least_conn;  # 最少连接数优先,更智能
    server 192.168.1.10:8080 weight=5;
    server 192.168.1.11:8080 weight=5;
    server 192.168.1.12:8080 backup;  # 备用节点
}
server {
    listen 80;
    server_name api.example.com;
    # 跨域配置(前后端分离必需)
    location /api/ {
        # 处理预检请求
        if ($request_method = 'options') {
            add_header 'access-control-allow-origin' 'https://frontend.example.com';
            add_header 'access-control-allow-methods' 'get, post, put, delete, options';
            add_header 'access-control-allow-headers' 'dnt,user-agent,x-requested-with,if-modified-since,cache-control,content-type,range,authorization';
            add_header 'access-control-allow-credentials' 'true';
            add_header 'access-control-max-age' 1728000;
            add_header 'content-type' 'text/plain; charset=utf-8';
            add_header 'content-length' 0;
            return 204;
        }
        proxy_pass http://backend;
        proxy_http_version 1.1;
        # 关键:传递 cookie 和 session id
        proxy_set_header host $host;
        proxy_set_header x-real-ip $remote_addr;
        proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
        proxy_set_header x-forwarded-proto $scheme;
        # 确保 cookie 透传
        proxy_pass_header set-cookie;
        proxy_cookie_path / /;
        proxy_cookie_domain backend.example.com .example.com;
    }
}

3. 其他 session 存储方案对比

方案优点缺点适用场景
redis速度快,支持过期,分布式友好需额外维护 redis高并发,大规模集群
mysql/postgresql持久化好,已有数据库复用性能较低,频繁读写压力大小规模,已有数据库
memcached纯内存,极快无持久化,数据易失纯缓存场景,可容忍丢失
jwt(无 session)服务端无状态,天然分布式token 无法主动失效,体积大微服务,api 网关

方案三:jwt token 替代 session(无状态架构)

彻底抛弃服务端 session,改用 token 认证。

认证流程

1. 用户登录 → 后端验证 → 生成 jwt(含用户id、权限、过期时间)
                    ↓
2. 返回 token 给前端 → 前端存储(localstorage 或 cookie)
                    ↓
3. 后续请求 → 前端在 header 携带 authorization: bearer <token>
                    ↓
4. nginx 透传 → 后端验签 → 无需查 session,直接获取用户信息

nginx 配置(jwt 透传)

server {
    listen 80;
    server_name api.example.com;
    location /api/ {
        proxy_pass http://backend;
        # 关键:透传 authorization header
        proxy_set_header authorization $http_authorization;
        proxy_pass_header authorization;
        # 其他标准配置
        proxy_set_header host $host;
        proxy_set_header x-real-ip $remote_addr;
        proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
        # 可选:nginx 层 jwt 验签(减轻后端压力,需 ngx_http_auth_jwt_module)
        # auth_jwt "api";
        # auth_jwt_key_file /etc/nginx/jwt_key.pub;
    }
}

jwt vs session 对比

特性session + redisjwt
服务端状态有状态(存 redis)无状态
横向扩展需 redis 集群天然支持
登出/踢人立即删除 session需黑名单机制(redis)
性能每次查 redis本地验签,更快
安全性可控制,服务端掌握token 泄露后无法撤销(除非短过期+刷新)
适用传统 web,需强控制微服务,移动端,api

方案四:nginx + lua 实现共享 session(openresty)

在 nginx 层统一处理 session,后端完全无感知。

# 使用 openresty + lua-resty-session
server {
    listen 80;
    server_name app.example.com;
    location / {
        access_by_lua_block {
            local session = require "resty.session".start()
            -- 检查登录状态
            if not session.data.user_id then
                -- 未登录,重定向到登录页
                return ngx.redirect("/login")
            end
            -- 已登录,将用户信息注入 header 传给后端
            ngx.req.set_header("x-user-id", session.data.user_id)
            ngx.req.set_header("x-user-role", session.data.role)
        }
        proxy_pass http://backend;
    }
    location /login {
        content_by_lua_block {
            -- 处理登录逻辑,写 session 到 redis
            local session = require "resty.session".start()
            session.data.user_id = ngx.var.arg_username
            session.data.role = "admin"
            session:save()
            ngx.say("login success")
        }
    }
}

优势:后端完全无 session 逻辑,专注业务;nginx 层统一认证入口。

生产环境推荐配置

完整 nginx 配置(redis session + 负载均衡)

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
    worker_connections 1024;
}
http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    # 日志格式(记录 session id)
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    'session=$cookie_session';  # 记录 session cookie
    access_log /var/log/nginx/access.log main;
    # 上游后端(无状态,纯轮询)
    upstream api_backend {
        zone backend 64k;
        least_conn;
        server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
        server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
        server 192.168.1.12:8080 max_fails=3 fail_timeout=30s;
        keepalive 32;  # 长连接,提升性能
    }
    # 前端静态资源(cdn 或本地)
    server {
        listen 80;
        server_name www.example.com;
        root /var/www/frontend;
        location / {
            try_files $uri $uri/ /index.html;
            expires 1h;
        }
        # 静态资源缓存
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires 30d;
            add_header cache-control "public, immutable";
        }
    }
    # api 网关
    server {
        listen 80;
        server_name api.example.com;
        # 安全头
        add_header x-frame-options "sameorigin" always;
        add_header x-content-type-options "nosniff" always;
        add_header x-xss-protection "1; mode=block" always;
        # 跨域(生产环境限制具体域名)
        map $http_origin $cors_origin {
            default "";
            "~^https?://(.*\.)?example\.com$" $http_origin;
            "~^https?://localhost:\d+$" $http_origin;
        }
        location /api/ {
            # cors 处理
            if ($request_method = 'options') {
                add_header 'access-control-allow-origin' $cors_origin;
                add_header 'access-control-allow-credentials' 'true';
                add_header 'access-control-allow-methods' 'get, post, put, delete, options';
                add_header 'access-control-allow-headers' 'accept,authorization,cache-control,content-type,dnt,if-modified-since,keep-alive,origin,user-agent,x-requested-with';
                add_header 'access-control-max-age' 1728000;
                add_header 'content-type' 'text/plain; charset=utf-8';
                add_header 'content-length' 0;
                return 204;
            }
            add_header 'access-control-allow-origin' $cors_origin always;
            add_header 'access-control-allow-credentials' 'true' always;
            proxy_pass http://api_backend;
            proxy_http_version 1.1;
            # 连接优化
            proxy_connect_timeout 5s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
            # 缓冲区
            proxy_buffering on;
            proxy_buffer_size 4k;
            proxy_buffers 8 4k;
            # 关键:session/cookie 透传
            proxy_set_header host $host;
            proxy_set_header x-real-ip $remote_addr;
            proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
            proxy_set_header x-forwarded-proto $scheme;
            proxy_set_header x-forwarded-host $host;
            proxy_set_header x-forwarded-port $server_port;
            # cookie 处理
            proxy_pass_header set-cookie;
            proxy_cookie_path / /;
            # 长连接
            proxy_set_header connection "";
        }
        # 健康检查(需 nginx_upstream_check_module)
        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header content-type text/plain;
        }
    }
}

方案选择建议

场景推荐方案理由
中小型项目,快速上线nginx ip_hash零代码改动,快速解决
中大型项目,长期维护redis session标准方案,生态成熟
微服务/云原生架构jwt + api 网关无状态,天然适合容器化
极高性能要求openresty lua session减少后端交互,nginx 层处理

核心原则:session 共享的本质是让状态外置,nginx 作为入口只需做好透明透传和负载均衡。

到此这篇关于nginx解决前后端分离架构下的session共享的几种方法的文章就介绍到这了,更多相关nginx session共享内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com