Запрос Cross-Origin блокируется только при загрузке / загрузке файлов

У меня есть приложение Angular, которое делает запрос к Spring Boot RESTful API. В целях разработки я установил различную свободную политику CORS в моей Spring Boot (обратите внимание, что при чтении этого и возможном копировании или вставке они не предназначены для безопасных производственных значений).

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCORSFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept, xsrf-token, authorization");

        response.setHeader("Access-Control-Expose-Headers", "Location");
        response.addHeader("Access-Control-Expose-Headers", "xsrf-token");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

Класс @Configuration, который его использует:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private SimpleCORSFilter corsFilter;

    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.addFilterBefore(corsFilter, ChannelProcessingFilter.class).authorizeRequests().antMatchers("/admin/**")
                .hasAnyAuthority("ROLE_ADMIN").antMatchers(HttpMethod.GET, "/public").permitAll().and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().httpBasic()
                .realmName("test").and().csrf().disable();

    }
}

Обычно связь между приложениями работает просто найти. Я могу без проблем получать и публиковать данные JSON. Однако всякий раз, когда я пытаюсь загрузить изображение или запустить код, который должен загрузить файл, я получаю следующую ошибку в консоли моего браузера (Firefox):

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8092/report/csv/detail. (Reason: CORS request did not succeed).

Конечная точка контроллера (Java):

@RequestMapping("/csv/detail")
public ResponseEntity<?> getDetailedCSV(@RequestBody ReportRequestDTO dto) {
    HttpHeaders headers = new HttpHeaders();
    byte[] contents;
    try {
        contents = IOUtils.toByteArray(new FileInputStream(reportService.getPDFSummary((dto))));
        headers.setContentType(MediaType.parseMediaType("application/pdf"));
        headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
        ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
        return response;
    } catch (FileNotFoundException ex) {
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    } catch (IOException ex) {
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);

    }
}

Метод getPDFSummary:

@Override
public String getPDFSummary(ReportRequestDTO req) {
    String outputName = outDir + UUID.randomUUID().toString() + ".pdf";
    List<SummaryReport> rows = new ArrayList<>();

    if (req.getStatusType() == ReportStatus.ALL) {
        rows = summaryRepo.getSummaryReportAllStatus(req.getPropertyIDs(), req.getItemIDs(), req.getStart(),
                req.getEnd());
    } else {
        boolean isOpen = req.getStatusType() == ReportStatus.OPEN;
        rows = summaryRepo.getSummaryReport(isOpen, req.getPropertyIDs(), req.getItemIDs(), req.getStart(),
                req.getEnd());
    }

    String html = convertRepsToHtml(rows);
    PdfConverterExtension.exportToPdf(outputName, html, "", options);
    return outputName;
}

Эта служба Angular, которая связывается с приложением Spring Boot:

@Injectable()
export class ReportService {
  private baseEndpoint: String = 'http://localhost:8092';
  constructor(private http: HttpClient) {}

  public getReport(req: ReportRequestModel): Observable<Blob> {
    return this.http.post(
      `${this.baseEndpoint}/report/${req.exportType}`,
      req,
      { responseType: 'blob' }
    );
  }
}

Хотя я и раньше сталкивался с подобными проблемами, я предполагал, что CORSFilter в моем коде Java предотвратил бы ошибку. Что мне не хватает?

Вы пробовали другой браузер, например Chrome?

user10527814 26.10.2018 20:23

В Chrome я действительно получаю разные ошибки: [Violation] 'load' handler took 891ms [Violation] Forced reflow while executing JavaScript took 62ms

KellyM 26.10.2018 21:15

Сообщение об ошибке Chrome помогло мне. Теперь проблема решена. Проблема заключалась в том, что приложение Java записывало в каталог assert приложения Angular, вынуждая его перекомпилировать и перезагружать (я использовал ng serve с Angular CLI). Спасибо.

KellyM 26.10.2018 21:24
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
3
1 253
1

Ответы 1

я не уверен, но полагаю, что этот ответ вам как-то поможет

Однажды я столкнулся с той же проблемой, и после изучения некоторых моментов я понял, что весенняя загрузка обеспечивает некоторый расширенный уровень безопасности для источников CORS, чтобы ограничить CROSS SITE ATTACK.

Мы обсудим это позже, сначала мы перейдем к делу,

Код, который вы написали в классе SimpleCORSFilter, в основном отвечает за безопасность на уровне заголовков, когда вы работаете с любым источником CORS.

Чтобы убедиться в этом, проверьте заголовок ответа, используя элемент inspect (точка - 1).

Проверьте каждый элемент заголовка, который вам требовался или использовался для выполнения вашего внешнего кода (код Anguler, как вы упомянули ранее). Для загрузки файла требуются некоторые параметры, такие как content-type, content-disposition. Я полагаю, вы не упомянули об этом должным образом или используете не в соответствии со стандартами пружинной загрузки (пункт 2).

Если этот параметр отсутствует, отправьте его в своем ответе, я не уверен, что ваш код работает или нет, но лучше, когда вы работаете с весенней загрузкой, отправляйте ваш составной файл как ресурс с каждым из параметров заголовка, например

content-type: MIME-тип файла, Content - Disposition: имя файла и действие, которое вы выполняете: вложение / встроенное (точка - 3).

В некоторых случаях все эти параметры все еще существуют, и вы все еще не можете загрузить (с чем я сталкиваюсь),

Решение заключается в том, что вы добавляете этот параметр в качестве ответа, но не разрешаете им доступ из источника CORS.

Для этого в «Access-Control-Expose-Headers» нужно указать какой-то обязательный параметр (Пункт - 4). также добавьте некоторые другие параметры, которые вы хотите добавить.

  1. Right Click browser -> select inspect element -> Go in network pane -> Click on requested url -> In newly open block you see the request and their relevant content -> Go in response header option

  2. Add debugger on front-end code -> console.info(“”)

  3. Go the end point -> Take Resource param -> Add file as OutputStream -> Send it as ResponseEntity

Path path = Paths.get(<directory-path>).normalize();
Path filePath = path.resolve(fileName).normalize();
Resource resource = new UrlResource(filePath.toUri());
Return ResponseEntity.ok
        .contentType(MediaType.<MIME-Type>)
        .header(HttpHeaders.CONTENT_DISPOSITION, “attachment; filename=””+ resource.filename())
        .body(resource);
  1. SimpleCORSFilter class -> doFilter() method -> add
response.setHeader(“Access-Control-Expose-Headers”, “xsrf-token, X-Total-Results, Authorization, Content-type, Content-Disposition”)

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

Другие вопросы по теме