You need to enable JavaScript to run this app. 已配置flask-cors解决GET跨域,vue.js发POST登录请求仍被CORS拦截
优惠活动
大模型
产品
解决方案
定价
更多

已配置flask-cors解决GET跨域,vue.js发POST登录请求仍被CORS拦截

跨域问题排查说明

现状梳理

当前技术栈与已做配置:

  • 前端:Vue.js + vue-resource,本地开发地址http://localhost:8080
  • 后端:Flask-restful 开发的REST API,本地运行地址http://127.0.0.1:5000
  • 已通过flask_cors全局初始化解决普通GET请求的跨域问题,现在调用登录POST接口时,被浏览器CORS策略拦截,报错内容:

位于'http://127.0.0.1:5000/api/auth/login'的XMLHttpRequest请求被CORS策略拦截:来自源'http://localhost:8080'的请求的预检响应未通过访问控制检查,未返回HTTP OK状态。

相关代码参考

后端初始化跨域的代码(__init__.py)

from flask_cors import CORS, cross_origin

app = Flask(__name__)
CORS(app)

登录接口实现

class LoginApi(Resource):
    def post(self):
        try:
            data = request.get_json(force=True) 
            user = User.objects.get(email=data.get('email'))
            authorized = user.check_password(data.get('password'))
            if not authorized:
                return {'error': 'Email or password invalid'}, 401
        
            expires = datetime.timedelta(days=7)
            access_token = create_access_token(identity=str(user.id), expires_delta=expires)
            return {'token': access_token}, 200
        except (UnauthorizedError, DoesNotExist):
            raise UnauthorizedError
        except Exception:
            raise InternalServerError

前端全局配置(main.js)

import VueResource from 'vue-resource'

Vue.use(VueResource)
Vue.http.options.root = process.env.API_URL ? process.env.API_URL : 'http://127.0.0.1:5000/';

登录触发与接口封装代码

// 页面触发登录的方法
save () {
    this.service = new UserService(this.$resource)
    this.service
        .login(this.user)
        .then(res => console.log(res), error => console.log(error))
}

// UserService接口封装类
export default class UserService {
    constructor(resource) {
        this._resource = resource("api/auth/login")
    }

    login (user) {
        return this._resource
            .save(user)
    }
}

问题根因与对应解决方法

  1. 预检请求触发的405错误
    GET请求能正常访问,是因为GET属于CORS规则中的“简单请求”,不需要经过预检阶段。而带application/json请求头的POST请求属于非简单请求,浏览器会自动先发送一个OPTIONS方法的预检请求到接口,确认后端的跨域允许规则后,才会发起真正的POST业务请求。
    原来的CORS(app)初始化逻辑只会给路由正常处理返回的响应添加跨域头,不会替路由接管OPTIONS方法的匹配逻辑。当前登录接口只实现了post方法的处理逻辑,当OPTIONS请求打到这个路由上时,Flask-restful会直接返回405 Method Not Allowed的状态,这个响应没有携带CORS需要的跨域头,且状态不是200,直接触发浏览器的拦截规则。
    解决方法二选一即可:
    • 优化全局CORS初始化配置,让flask_cors自动处理所有业务路由的OPTIONS预检请求,替代原来的简单CORS(app)写法:
      CORS(
          app,
          resources={r"/api/*": {"origins": "http://localhost:8080"}},
          supports_credentials=True,
          allow_headers="Content-Type, Authorization",
          methods=["GET", "POST", "OPTIONS"]
      )
      
    • 手动在LoginApi类中添加options方法处理预检请求,直接返回200状态和对应的跨域响应头:
      class LoginApi(Resource):
          def options(self):
              return {}, 200, {
                  'Access-Control-Allow-Origin': 'http://localhost:8080',
                  'Access-Control-Allow-Methods': 'POST, OPTIONS',
                  'Access-Control-Allow-Headers': 'Content-Type, Authorization'
              }
      
          # 原有post业务逻辑保持不变
          def post(self):
              pass
      
  2. 异常抛出导致的跨域头缺失
    原代码中遇到用户不存在、密码校验失败等异常场景时,是通过抛出UnauthorizedError、InternalServerError的方式生成响应。这类由异常生成的响应,flask_cors可能无法自动为其添加跨域头,就算预检通过,实际业务请求返回401/500状态时,因为缺少跨域头,依然会被浏览器拦截。
    调整为直接返回带状态码的响应,替代抛出异常的写法即可:
    try:
        # 原有业务逻辑
        pass
    except (UnauthorizedError, DoesNotExist):
        return {'error': 'Email or password invalid'}, 401
    except Exception:
        return {'error': 'Internal server error'}, 500
    
  3. 请求头匹配校验
    确认vue-resource发起POST请求时携带的Content-Type值,需要和CORS配置中允许的请求头列表完全一致,比如当前场景要确保允许application/json类型的请求头,否则预检请求会因为头不匹配失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.02 11:15:06