Почему появляется OPTIONS? Междоменное решение интерфейса SpringBoot

Spring Boot Java

Оригинальный адрес:xeblog.cn/articles/12

введение

Несмотря на то, что интерфейсные и внутренние проекты разделены, степень связи снижается, но также возникают различные проблемы. Внутренний проект развертывается Tomcat (прослушивание порта 8080), а внешний проект развертывается на Nginx (прослушивание портов, отличных от 8080, таких как 80, 443), скорость загрузки внешней страницы значительно повышается. , но сообщается об ошибке, когда ajax запрашивает внутренний интерфейс.

image

Та же политика происхождения

Политика того же происхождения — хорошо известная политика безопасности, предложенная Netscape. Все браузеры, поддерживающие JavaScript, теперь используют эту стратегию. Так называемый гомологичный означает, что доменное имя, протокол и порт совпадают.

Внешний адрес:http://127.0.0.1:63344

Адрес бэкенда:http://127.0.0.1:8080

Хотя IP-адреса и протоколы этих двух адресов одинаковы, порты разные, поэтому они не соответствуют одному и тому же происхождению, что вызывает междоменные проблемы.

решение

Настройка addCorsMappings

Добавьте реализацию классаWebMvcConfigurerИнтерфейс, а затем добавить этот класс@ConfigurationПримечания, наконец, понялиaddCorsMappingsметод в порядке.

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
	@Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
                .maxAge(3600)
                .allowCredentials(true);
    }
}

нормальный запрос

image

Это конец? Это так просто?

Войдите в фоновое управление

image

wtf?

image

Почему запрос OPTIONS?

按照我的逻辑,上面那个报错的接口应该是一个GET请求,可为什么发的是OPTIONS请求?翻阅各种资料,各种百度google,各种倒腾,各种头疼,最后。 . .我掀开了被子,惊奇的发现。 . .被窝可真暖和啊! (先睡一觉再说)

image

image

причина

Получается, что браузер перед отправкой реального запроса отправит предварительный запрос с методом OPTIONS.Preflighted requestsЭтот запрос используется для проверки того, является ли запрос безопасным, и не все запросы будут отправлены при соблюдении следующих условий:

  • Метод запроса не GET/HEAD/POST
  • Content-Type запроса POST не является application/x-www-form-urlencoded, multipart/form-data или text/plain.
  • В запросе установлено настраиваемое поле заголовка

Для интерфейса со стороны управления я должен проверить разрешения интерфейса, и каждый запрос должен содержать настраиваемое поле (токен) в заголовке, поэтому браузер отправит еще один запрос OPTIONS.

Почему OPTIONS запрашивают ошибку. . .

После отладки было обнаружено, что запрос OPTIONS несет только настраиваемые поля и не вносит соответствующие значения. Когда поле токена проверяется в фоновом режиме, токенNULL, поэтому проверка завершается неудачно и выдается исключение.

image

ВАРИАНТЫ выпуска

Я переключился на междоменное решение, используя перехватчик для решения междоменной проблемы и отпустив запрос OPTIONS.

Добавьте класс перехватчикаCorsInterceptorвыполнитьHandlerInterceptorинтерфейс

@Component
public class CorsInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "86400");
        response.setHeader("Access-Control-Allow-Headers", "*");

        // 如果是OPTIONS则结束请求
        if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
            response.setStatus(HttpStatus.NO_CONTENT.value());
            return false;
        }

        return true;
    }
}

Нужно проверить на перехватчик перехватчика перехвата пересекания пересекания выше

Ставлю оригинальную междоменную конфигурациюaddCorsMappingsудален

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Resource
    private LoginInterceptor loginInterceptor;
    @Resource
    private CorsInterceptor corsInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
		// 跨域拦截器需放在最上面
        registry.addInterceptor(corsInterceptor).addPathPatterns("/**");
		// 校验token的拦截器
        registry.addInterceptor(loginInterceptor).addPathPatterns("/admin/**");
    }

}

запрос OPTIONS в порядке

image

GET-запросы также отправляются последовательно

image

Суммировать

Спокойной ночи!

image

Добавка

Access-Control-Allow-Credentials响应头表示是否可以将对请求的响应暴露给页面。 возвращениеtrueтогда да, никаких других значений. Полномочия могут бытьcookies, authorization headersилиTLS client certificates. Если установлено значение true, сервер НЕ ДОЛЖЕН устанавливатьAccess-Control-Allow-Originзначение*, нужно указать доменное имя, иначе при необходимости отправитьCookieКогда браузер отвечает, браузер отвечает.

контрольная работа

Ajax-запрос включенwithCredentialsАтрибуты

xhrFields: {
	withCredentials: true
}

Когда внутренняя междоменная конфигурация остается неизменной, результат запроса браузера сообщает об ошибке.

image

уточнитьAccess-Control-Allow-Originзначениеhttp://127.0.0.1:63344, Нормальный запрос снова

image

Окончательная конфигурация

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
		// 此处配置的是允许任意域名跨域请求,可根据需求指定
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "86400");
        response.setHeader("Access-Control-Allow-Headers", "*");

        // 如果是OPTIONS则结束请求
        if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
            response.setStatus(HttpStatus.NO_CONTENT.value());
            return false;
        }

        return true;
    }

Ссылаться на