проблема cors при создании исключения времени выполнения с пружиной и docker - PullRequest
6 голосов
/ 05 апреля 2020

Я создаю веб-приложение с использованием Spring, angular и docker. У меня также есть на данный момент две среды. Среда разработки, где angular подается с использованием npm start, а пружина с использованием mvn spring-boot:run. И тестовая среда, в которой я использую digitalocean для размещения своего приложения и контейнера angular и весенних приложений, используя docker.

В этом приложении у меня есть страница регистрации, на которой пользователь может зарегистрироваться, и пружинный контроллер для обработки запроса на регистрацию. Вот код для моего контроллера:

@PostMapping("/register")
public SaveUserDto register(@RequestBody @Valid SaveUserDto saveUserDto, WebRequest request) {

        User userToSave = this.modelMapper.map(saveUserDto, User.class);
        User registeredUser = null;
        try {
            registeredUser = this.registrationService.register(userToSave);
        } catch (DataIntegrityViolationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            if(e.getRootCause().toString().contains("uk_pfki8mu6sefesty9h30d4n3yv")) {
                throw new EmailAlreadyExistException();
            }
        }
        try {
            eventPublisher.publishEvent(new OnRegistrationCompleteEvent(registeredUser, request.getLocale(), request.getHeader("Origin")));
        } catch (Exception me) {
            System.out.println(me.getMessage());
        }

        if(registeredUser != null) {
            return this.modelMapper.map(registeredUser, SaveUserDto.class);
        } else {
            return null;
        }
}

Поскольку мой angular подается с хоста: 4200 (где хост - это localhsot в моей среде разработки или 165.22.72.253 в моей тестовой среде) и мой API подается с хоста: 8761 У меня есть конфигурация cors для включения запроса cors. Вот конфигурация:

@Bean
public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://" + clientHost + ":4200");
        config.addAllowedOrigin("http://" + clientHost + ":80");
        config.addAllowedHeader("*");
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("DELETE");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
}

Здесь clientHost - это параметр, значение которого либо localhost при работе в среде dev, либо 165.22.72.253 для моей тестовой среды. В большинстве случаев этот параметр работает, но в одном конкретном случае происходит сбой.

Проблема возникает, когда пользователь пытается зарегистрировать существующий адрес электронной почты. Затем, как вы можете видеть из метода контроллера, я выкидываю исключение EmailAlreadyExistException. В dev env все работает отлично, то есть запрос возвращает код ошибки 500 с сообщением «Электронная почта уже существует». Но в тестовой среде я получаю Access to XMLHttpRequest at 'http://165.22.72.253:8762/register' from origin 'http://165.22.72.253:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource..

Если мне пригодится мой docker -компонентный файл:

version: "3.5"

services:

  tomcat-file:
    container_name: tomcat-file-server
    image: tomcat-file-server
    build:
      context: .
      dockerfile: tomcat-file.prod.dockerfile
    volumes:
      - /home/vetter_leo/medias:/usr/local/tomcat/src
    ports:
      - "8205:8205"

networks:
  default:
    external:
      name: helenos-network

На данный момент я не понимаю, почему он работает в dev env и не в тестовом env. Любая помощь будет оценена. Заранее спасибо.

Ответы [ 5 ]

3 голосов
/ 01 мая 2020

В конечном итоге я добавил обработчик к исключению в контроллере, который возвращает мне правильное сообщение: вот так:

@ExceptionHandler({ EmailAlreadyExistException.class })
public String handleException() {
    return "{\"error\": \"" + messages.getMessage("emailAlreadyExist", null, Locale.ENGLISH) + "\"}";
}
2 голосов
/ 28 апреля 2020

Так как он выдает ошибку в тестовой среде, которая размещается в DigitalOcean, вы исследовали, есть ли у них способ перезаписи политики CORS по умолчанию? https://www.digitalocean.com/docs/spaces/how-to/configure-cors/

2 голосов
/ 12 апреля 2020

Вы пробовали прокси вызовы API? В проекте angular вы можете создать файл proxy.conf.json и добавить следующие конфигурации.

{
  "/api": {
    "target": "http://localhost:3000",
    "secure": false
  }
}

Затем в package.json измените начало,

"start": "ng serve --proxy-config proxy.conf.json"

Если вы Если вы хотите сделать это со стороны psring, добавьте @CrossOrigin к контроллеру.

Но если вы думаете, что столкнетесь с той же проблемой на производстве, я советую использовать обратный прокси, такой как Nginx. Вы Angular приложение и API обслуживаются через один и тот же порт, но все API имеют префикс api . Со стороны Nginx вы можете фильтровать вызовы API с помощью префикса api и передавать их в прокси-сервер.

2 голосов
/ 28 апреля 2020

Spring boot использует контроллер ошибок по умолчанию. Вы можете предоставить свой собственный и добавить заголовок Access-Control-Allow-Credentials к ответу:

import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RestController
public class CustomErrorController implements ErrorController {

    @RequestMapping("/error")
    public String handleErrors(HttpServletRequest request, HttpServletResponse response) {
        response.addHeader("Access-Control-Allow-Credentials","true");
        String errorMessage = request.getAttribute(RequestDispatcher.ERROR_MESSAGE).toString();

        return errorMessage;
    }

    @Override
    public String getErrorPath() {
        return "/error";
    }
}
0 голосов
/ 10 апреля 2020

Может быть проблема в том, что возникает исключение до вызова фильтра cors?

Можете ли вы попробовать это?

  //...

  source.registerCorsConfiguration("/**", config);
  FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
  bean.setOrder(Ordered.HIGHEST_PRECEDENCE);

  return bean;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...