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

如何用Go代理预检请求并返回HTTP 200 OK状态?

解决CORS预检请求失败问题

场景还原

客户端请求代码

客户端通过fetch发送跨域POST请求:

<!DOCTYPE html>
<html>
    <body>
        <script>
            fetch('http://localhost:3000/messages', {
                method: 'POST',
                headers: { 'content-type': 'application/json' },
                body: JSON.stringify({ data: 'foo' })
            })
            .then(async response => {
                console.log(await response.json());
            });
        </script>
    </body>
</html>

代理服务器(端口3000)

作为请求转发代理,负责将请求传递到目标服务器:

import (
    "net/http"
    "net/http/httputil"
    "net/url"
)

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("/messages", handleRequest)

    http.ListenAndServe(":3000", mux)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers", "*")
    w.Header().Set("Access-Control-Allow-Methods", "*")

    targetUrl, _ := url.Parse("http://localhost:3001/messages")

    proxy := httputil.NewSingleHostReverseProxy(targetUrl)
    proxy.ServeHTTP(w, r)
}

目标服务器(端口3001)

处理实际业务请求并返回响应:

import (
    "encoding/json"
    "net/http"
)

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("/messages", handleRequest)

    http.ListenAndServe(":3001", mux)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers", "*")
    w.Header().Set("Access-Control-Allow-Methods", "*")

    w.WriteHeader(http.StatusOK)

    json.NewEncoder(w).Encode("bar")
}

问题表现

预期控制台输出bar,但实际出现CORS报错:

Access to fetch at 'http://localhost:3000/messages' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

错误截图

解决方法

问题核心是代理服务器未正确处理OPTIONS预检请求:当请求包含content-type: application/json这类非简单请求头时,浏览器会先发送OPTIONS请求确认服务器允许跨域,此时无需转发到目标服务器,直接在代理层返回200状态和CORS配置即可。

修改代理服务器代码

更新handleRequest函数,优先处理OPTIONS请求:

func handleRequest(w http.ResponseWriter, r *http.Request) {
    // 直接处理OPTIONS预检请求,返回200和CORS配置
    if r.Method == http.MethodOptions {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Headers", "*")
        w.Header().Set("Access-Control-Allow-Methods", "*")
        w.WriteHeader(http.StatusOK)
        return
    }

    // 其他请求正常转发到目标服务器
    w.Header().Set("Access-Control-Allow-Origin", "*")
    targetUrl, _ := url.Parse("http://localhost:3001/messages")
    proxy := httputil.NewSingleHostReverseProxy(targetUrl)
    proxy.ServeHTTP(w, r)
}

优化目标服务器(可选)

由于CORS逻辑已在代理层处理,目标服务器可移除冗余的CORS头配置:

func handleRequest(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode("bar")
}

原因说明

之前的代码将OPTIONS请求直接转发到目标服务器,虽然目标服务器设置了CORS头,但代理转发过程中可能导致响应状态或头信息不符合浏览器的预检要求。在代理层直接处理OPTIONS请求,能确保预检请求快速通过,后续的POST请求再正常转发处理业务逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 22:50:24