You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker+Traefik架构下Python后端Session无法传递至React前端

跨域场景下Session/Cookie无法传递问题排查与解决

问题背景

后端运行在Docker容器,前端在独立容器,Traefik做负载均衡。后端地址http://test-backend.localhost/api/test,前端地址http://test-frontend.localhost/#/one。当前遇到两个问题:

  1. 前端发送POST请求后,后端已成功创建Session,但浏览器未设置对应的Cookie;
  2. 开启withCredentials: true后,Firefox出现跨域错误:

跨源请求被阻止:同源策略不允许读取位于‘http://test-backend.localhost/api/test’的远程资源。(原因:如果CORS头‘Access-Control-Allow-Origin’为‘*’,则不支持凭证)

后端CherryPy代码

class Test(object):
    exposed = True

    @property
    def db(self):
        return cherrypy.request.db    
   

    @cherrypy.tools.accept(media='text/plain')
    def GET(self):
        cherrypy.session['something'] = "test"
        return Service.get_service(self)

    @cherrypy.tools.json_in()
    @cherrypy.tools.json_out()    
    def POST(self):
        cherrypy.session['something'] = "john"
        cookie = cherrypy.request.cookie
        if 'uid' in cookie.keys():
            uid = cookie['uid'].value
        if 'uid' not in cookie.keys():
            uid = 'uid' + datetime.datetime.utcnow().strftime("%Y%m%d%H%M%S")
            cookie = cherrypy.response.cookie            
            cookie['uid'] = uid
            cookie['uid']['expires'] = 3600
            cookie['uid']['path'] = '/'
            cookie['uid']['secure'] = True
        
        # Manually set the session cookie in the response headers
        cherrypy.response.headers['Set-Cookie'] = str(cookie)


        input_json = cherrypy.request.json
        print("session is", cherrypy.session.id)

        print(input_json)       
      
        # Validate the Request JSON data
        # try:
        #     schema = HitSchema()
        #     validated_data = schema.load(query_string)
        #     return Service.post_service(self, query_string, cherrypy.response.cookie)

        # except ValidationError as e:
        #     cherrypy.response.status = 400
        #     return {"error": str(e)}
        # Add the appropriate return statement here
        return "POST request processed successfully"        


    def OPTIONS(self):
        # Handle preflight request
        cherrypy.response.headers['Access-Control-Allow-Credentials'] 
           = 'true'
        cherrypy.response.headers['Access-Control-Allow-Origin'] = '*'
        cherrypy.response.headers['Access-Control-Allow-Methods'] = 'GET, POST'
        cherrypy.response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, Accept, X-Requested-With, Origin, Access-Control-Allow-Headers'

前端React代码

初始写法:

const mutation = useMutation((newTodo: any) => {
    return axios.post('http://test-backend.localhost/api/test', newTodo);
});

尝试开启凭证传递后的写法:

const mutation = useMutation((newTodo: any) => {
    return axios.post('http://test-backend.localhost/api/hit', newTodo, {
        withCredentials: true,
    });
});

核心问题分析

  1. CORS配置冲突:当开启withCredentials: true时,浏览器要求Access-Control-Allow-Origin不能设为*,必须指定具体的前端域名,否则会触发同源策略限制。
  2. Cookie设置问题:后端手动设置Set-Cookie的方式可能覆盖CherryPy默认的Session Cookie,且secure: true在非HTTPS的localhost环境下会导致浏览器拒绝保存Cookie。
  3. 预请求(OPTIONS)处理:OPTIONS请求的CORS配置需要与实际请求保持一致,且要正确返回允许凭证的头信息。

解决方案步骤

1. 修改后端CORS配置,指定具体允许的Origin

替换OPTIONS方法中的Access-Control-Allow-Origin为前端实际域名,推荐动态获取请求头中的Origin:

def OPTIONS(self):
    # 获取请求头中的Origin,动态返回允许的域名
    origin = cherrypy.request.headers.get('Origin', '')
    cherrypy.response.headers['Access-Control-Allow-Credentials'] = 'true'
    cherrypy.response.headers['Access-Control-Allow-Origin'] = origin
    cherrypy.response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
    cherrypy.response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, Accept, X-Requested-With, Origin'

注:如果需要允许多个域名,可以维护一个白名单,判断请求Origin是否在白名单内再返回。

2. 修复Cookie设置逻辑

  • 移除手动设置Set-Cookie的代码,CherryPy会自动处理Session Cookie的设置
  • 开发环境注释掉secure: true(localhost用HTTP,secure Cookie无法被保存;生产环境HTTPS时再开启)
  • 确保Cookie的path设置正确,允许跨路径访问

修改POST方法中的Cookie创建部分:

if 'uid' not in cookie.keys():
    uid = 'uid' + datetime.datetime.utcnow().strftime("%Y%m%d%H%M%S")
    cookie = cherrypy.response.cookie            
    cookie['uid'] = uid
    cookie['uid']['expires'] = 3600
    cookie['uid']['path'] = '/'
    # 开发环境注释掉secure,生产HTTPS环境再开启
    # cookie['uid']['secure'] = True

同时删除这行手动设置Cookie的代码:

# cherrypy.response.headers['Set-Cookie'] = str(cookie)

3. 确保前端请求正确携带凭证

保持withCredentials: true的配置,注意请求路径要与后端接口一致(之前代码中请求路径是/api/hit,后端是/api/test,需统一):

const mutation = useMutation((newTodo: any) => {
    return axios.post('http://test-backend.localhost/api/test', newTodo, {
        withCredentials: true,
    });
});

4. 验证Session Cookie的传递

  • 打开浏览器开发者工具,查看Application > Cookies,确认uid和CherryPy默认的Session Cookie(通常名为session_id)是否被保存
  • 查看后续请求头中的Cookie字段,确认是否携带这些Cookie

额外注意事项

  • Traefik配置:确保Traefik没有修改或移除响应头中的Set-Cookie和CORS相关头信息
  • Cookie SameSite属性:如果需要跨域传递Cookie,生产HTTPS环境可设置SameSite: 'None'(需配合secure: true);开发环境可设为SameSite: 'Lax'或'Strict'
  • CherryPy Session配置:确保后端已正确配置Session存储(如内存、文件或数据库),Session ID能正常生成和传递

内容的提问来源于stack exchange,提问作者jeril

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:24:58