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

Golang MySQL服务重定向时出现CORS跨域请求阻塞错误排查

解决跨域登录重定向的CORS错误及Go服务优化

核心问题分析

  • 跨域AJAX请求中,后端返回的重定向(3xx状态码)不会被浏览器自动执行,浏览器会拦截响应并触发CORS错误——重定向后的资源依然跨域,且当前代码的CORS头设置未覆盖重定向场景,导致preflight检查失败。
  • 你当前的逻辑是后端直接重定向,但跨域场景下这种方式不适用,浏览器不会跟随重定向跳转,反而会因为响应头不符合CORS规则报错。

解决方案:前端主导跳转(推荐)

跨域场景下,后端应返回登录结果的JSON数据,由前端页面根据结果自行处理跳转。修改loginHandler代码如下:

func loginHandler(w http.ResponseWriter, r *http.Request) {
    log.Println("Received request to loginHandler")

    // 确保所有响应都携带CORS头
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
    w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")

    if r.Method == http.MethodOptions {
        w.WriteHeader(http.StatusOK)
        return
    }

    if r.Method != http.MethodPost {
        http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
        return
    }

    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        log.Println("Error reading request body:", err)
        http.Error(w, "Failed to read request body", http.StatusInternalServerError)
        return
    }

    if len(body) == 0 {
        http.Error(w, "Empty request body", http.StatusBadRequest)
        return
    }

    var creds Credentials
    err = json.Unmarshal(body, &creds)
    if err != nil {
        log.Println("Error decoding request body:", err)
        http.Error(w, "Invalid request body", http.StatusBadRequest)
        return
    }

    log.Printf("Received credentials: %+v", creds)

    success, err := CheckCredentials(creds)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // 返回JSON结果,交由前端处理跳转
    w.Header().Set("Content-Type", "application/json")
    if success {
        json.NewEncoder(w).Encode(map[string]interface{}{
            "success":      true,
            "redirectUrl": "/gui/dashboard.html",
        })
    } else {
        json.NewEncoder(w).Encode(map[string]interface{}{
            "success":      false,
            "redirectUrl": "/gui/index.html",
        })
    }
}

前端配套处理示例(JS):

fetch('http://localhost:8080/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({username: '你的用户名', password: '你的密码'})
})
.then(res => res.json())
.then(data => {
  window.location.href = data.redirectUrl;
})
.catch(err => console.error(err));

额外优化建议

  1. 数据库连接池优化
    当前CheckCredentials每次请求都打开/关闭数据库连接,性能极低。建议初始化全局连接池复用连接:
// 全局连接池,程序启动时初始化
var db *sql.DB

func init() {
    var err error
    db, err = sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/dbname")
    if err != nil {
        log.Fatal("Failed to init database:", err)
    }
    // 设置连接池参数
    db.SetMaxOpenConns(20)
    db.SetMaxIdleConns(10)
}

func CheckCredentials(creds Credentials) (bool, error) {
    log.Println("Checking if the username and password are valid and not expired")

    var count int
    // 使用全局连接池查询
    err := db.QueryRow("SELECT COUNT(*) FROM users WHERE username = ? AND password = ? AND expires_at > NOW()", creds.Username, creds.Password).Scan(&count)
    if err != nil {
        log.Println("Failed to query the database:", err)
        return false, fmt.Errorf("failed to query the database: %w", err)
    }

    return count > 0, nil
}
  1. 密码安全优化
    代码中直接存储和传输明文密码,存在严重安全隐患。应使用bcrypt哈希算法存储密码,验证时比对哈希值:
// 存储用户时生成密码哈希
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(rawPassword), bcrypt.DefaultCost)

// 登录验证时比对哈希
err := bcrypt.CompareHashAndPassword([]byte(storedHash), []byte(creds.Password))
if err == nil {
    // 密码匹配成功
}
  1. CORS头安全性细化
    不要使用*作为Access-Control-Allow-Origin,应指定具体的前端域名,避免任意跨域请求:
w.Header().Set("Access-Control-Allow-Origin", "http://你的前端域名:端口")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 01:17:29