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

本地开发环境中PUT请求预检OPTIONS的Access-Control-Expose-Headers失效

CORS问题:PUT请求预检OPTIONS中的Access-Control-Expose-Headers被忽略,无法获取自定义响应头

问题说明

本地开发时遇到CORS相关问题:针对PUT请求的预检OPTIONS响应里的Access-Control-Expose-Headers被浏览器忽略,导致JavaScript代码无法获取指定的自定义响应头,控制台输出null而非服务器返回的my-value头值。

复现步骤

  • 修改/etc/hosts添加两个域名:
    127.0.0.1 locala.test
    127.0.0.1 localb.test
    
  • 将以下代码保存为cors.py,执行python cors.py启动服务:
    from http.server import BaseHTTPRequestHandler, HTTPServer
    
    class MyServer(BaseHTTPRequestHandler):
    
        # 提供发起CORS请求的页面,访问地址:http://locala.test:8080/
        def do_GET(self):
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write('''
                <html>
                <head><title>CORS Example</title></head>
                <body>
                    <p>Web page that makes a CORS request</p>
                    <script>
                        fetch('http://localb.test:8080/', {
                            method: 'PUT'
                        }).then((response) => {
                            // 预期输出x-my-custom的值,实际输出null
                            console.log(response.headers.get('x-my-custom'));
                        })
                    </script>
                </body>
                </html>
            '''.encode('utf-8'))
    
        # 处理预检OPTIONS请求,对应地址:http://localb.test:8080/
        def do_OPTIONS(self):
            self.send_response(204)
            self.send_header("Access-Control-Allow-Origin", "http://locala.test:8080")
            self.send_header("Access-Control-Allow-Methods", "PUT")
            self.send_header("Access-Control-Expose-Headers", "x-my-custom")
            self.end_headers()
    
        # 处理PUT请求,对应地址:http://localb.test:8080/
        def do_PUT(self):
            self.send_response(200)
            self.send_header("Access-Control-Allow-Origin", "http://locala.test:8080")
            self.send_header("x-my-custom", 'my-value')
            self.end_headers()
    
    webServer = HTTPServer(('127.0.0.1', 8080), MyServer)
    print('Running. Press CTRL+C to stop.')
    try:
        webServer.serve_forever()
    except KeyboardInterrupt:
        pass
    webServer.server_close()
    print('Stopped')
    
  • 在浏览器访问http://locala.test:8080即可复现问题。

解决方案

核心问题:Access-Control-Expose-Headers需要放在实际的PUT响应中,而非预检OPTIONS响应里。

浏览器仅会检查实际请求(此处为PUT)的响应头中的Access-Control-Expose-Headers,以此决定哪些自定义头可被JavaScript访问,预检OPTIONS响应中的该头是无效的。

修改do_PUT方法,添加Access-Control-Expose-Headers头:

def do_PUT(self):
    self.send_response(200)
    self.send_header("Access-Control-Allow-Origin", "http://locala.test:8080")
    self.send_header("Access-Control-Expose-Headers", "x-my-custom")  # 新增此行
    self.send_header("x-my-custom", 'my-value')
    self.end_headers()

修改后重启服务,再次访问页面,控制台会正确输出my-value。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 00:01:03