Как победить OPTIONS при CORS?
Только вчера разбирался для своего проекта по учёту долгов https://debtstracker.io/ и победил.
На OPTIONS надо возвращать 200 с заголовками и пустой ответ.
Я руководствовался этой схемой:
Вот мой работающий код на Go:func getOnly(handler HttpHandler) HttpHandler {
	return func(w http.ResponseWriter, r *http.Request) {
		c := appengine.NewContext(r)
		if r.Method == "OPTIONS" {  // Preflight request
			origin := r.Header.Get("Origin")
			switch origin {
			case "http://localhost:8080":
			case "http://localhost:8100":
			case "https://debtstracker.local":
			case "https://debtstracker.io":
			case "":
				BadRequest(c, w, errors.New("Missing required request header: Origin"))
				return
			default:
				err := errors.New(fmt.Sprintf("Unknown origin: %v", origin))
				log.Debugf(c, err.Error())
				BadRequest(c, w, err)
				return
			}
			log.Debugf(c, "Request 'Origin' header: %v", origin)
			if accessControlRequestMethod := r.Header.Get("Access-Control-Request-Method"); accessControlRequestMethod != "GET" {
				BadRequest(c, w, errors.New("Not a valid preflight request"))
				return
			}
			responseHeader := w.Header()
			responseHeader.Set("Access-Control-Allow-Methods", "GET")
			if accessControlRequestHeaders := r.Header.Get("Access-Control-Request-Headers"); accessControlRequestHeaders != "" {
				log.Debugf(c, "Request Access-Control-Request-Headers: %v", accessControlRequestHeaders)
				responseHeader.Set("Access-Control-Allow-Headers", accessControlRequestHeaders)
			} else {
				log.Debugf(c, "Request header 'Access-Control-Allow-Headers' is empty or missing")
				// TODO(security): Is it wrong to return 200 in this case?
			}
			responseHeader.Set("Access-Control-Allow-Origin", origin)
			w.WriteHeader(200)
			return
		}
		if r.Method != "GET" {
			BadRequest(c, w, errors.New(fmt.Sprintf("Expecting to get request method GET, got: %v", r.Method)))
			return
		}
		handler(w, r)
	}
}
Касательно YII2 в базовом контроллере нужно указать поведение для CORS: public function behaviors()
    {
        return [
            'corsFilter' => [
                'class' => Cors::className(),
            ],
            'authenticator' => [
                'class' => HttpBearerAuth::className(),
                'except' => ['options'],
            ],
        ];
    }