Контроллер Spring Boot не отвечает на запрос POST - PullRequest
9 голосов
/ 31 мая 2019

Я работаю с чековым принтером с облачной функцией.Он связывается со спецификацией сервера, которую я реализую.Он опрашивает URL с запросами POST каждые x секунд, и когда ответ POST содержит определенную часть информации, принтер отправляет GET-запрос на тот же URL-адрес, чтобы получить информацию для печати. ​​

Я реализуюсервер печати как сервер Spring Boot, и я получаю некоторые странные проблемы с методом POST, с которыми мне нужна помощь.

Моя проблема заключается в том, что запросы POST от принтера к серверу никогда не поступают в контроллер.Тем не менее, я могу отправить запрос POST от Почтальона на тот же URL-адрес, и он обрабатывается контроллером.

URL-адрес просто: https://www.[my -domain] .com: [порт-number] / cloudprint

Также я попытался скопировать метод контроллера в другое приложение Spring (не Boot), работающее на экземпляре Tomcat за Apache, и там обрабатываются POST-запросы от принтерапо методу контроллера.Я вижу их в журнале Apache и журнале Tomcat.Частота опроса в настоящее время составляет 10 секунд.

Вот как выглядит контроллер:

package com.[my-domain].[application-name].controller;

[a bunch of imports]

@RestController
@CrossOrigin
public class PrintController {
    Logger logger = LoggerFactory.getLogger(PrintController.class);

    @RequestMapping(value="/cloudprint", method=RequestMethod.POST,
            headers={"Accept=application/json"})
    @ResponseStatus(HttpStatus.CREATED)
    public @ResponseBody String printPost() { 
        logger.debug("in printPost");
        return "OK";
    }

    @RequestMapping(value="/cloudprint", method=RequestMethod.GET,
            headers={"Accept=application/json"})
    @ResponseStatus(HttpStatus.OK)
    public @ResponseBody String printGet(HttpServletRequest request) {
        logger.debug("in printGet");
        return "OK";
    }

    @RequestMapping(value="/cloudprint", method=RequestMethod.DELETE,
            headers={"Accept=application/json"})
    @ResponseStatus(HttpStatus.OK)
    public @ResponseBody String printDelete() {
        logger.debug("in printDelete");
        return "OK";
    }
}

Что может быть причиной этого?Что я могу проверить, чтобы решить эту проблему?

--- ДОБАВЛЕННАЯ ИНФОРМАЦИЯ НИЖЕ 2019-06-03 @ 13: 21 cet --- Поскольку у меня есть обычное Spring-приложение (без загрузки), которое принимает POSTзапросы от принтера, я могу записать информацию во входящем запросе.Итак, я сделал это.

Это один из запросов POST от принтера, который НЕ принимается контроллером загрузки Spring:

auth type: null
content type: application/json
-- HEADERS --
Header: host : dev.[our-domain-name].com
Header: accept : */*
Header: user-agent : Cente HTTPc
Header: content-type : application/json
Header: content-length : 303
Header: connection : keep-alive
QueryString: null
-- PARAMETERS --
END

Это один из запросов POST от Postman.на тот же URL-адрес, который принимается загрузочным контроллером Spring:

auth type: null
cotent type: application/json
-- HEADERS --
Header: content-type : application/json
Header: cache-control : no-cache
Header: Postman-Token : caf99fa1-4730-4193-aab3-c4874273661d
Header: user-agent : PostmanRuntime/7.6.0
Header: accept : */*
Header: host : dev.[our-domain-name].com
Header: accept-encoding : gzip, deflate
Header: content-length : 0
Header: connection : keep-alive
QueryString: null
-- PARAMETERS --
END

Анализ: 1. Заголовки агента пользователя различаются.2. Заголовки длины содержимого отличаются.3. В запросе почтальона есть три заголовка, которых нет у запроса от облачного принтера.Это: управление кешем, токен почтальона и кодировка приема

--- ДОБАВЛЕННАЯ ИНФОРМАЦИЯ НИЖЕ 2019-06-03 @ 17: 56 cet --- ОК, я понял, как записать тело сообщения,Это хорошо отформатированная структура json, которая на самом деле состоит из 303 символов:

{"status": "29 a 0 0 0 0 0 0 0 0 0 0",
 "printerMAC": "00:11:62:1b:xx:xx",
 "statusCode": "200%20OK",
 "printingInProgress": false,
 "clientAction": null,
 "display": [
   {"name": "MainDisplay" ,
    "status": {"connected": false}}],
 "barcodeReader": [
   {"name": "MainBCR" ,
    "status": {"connected": false,"claimed": false}}]}

Я создал соответствующие классы и изменил метод POST в приложении Boot следующим образом:

@RequestMapping(value="/cloudprint", method=RequestMethod.POST,
        headers={"Accept=application/json"})
@ResponseStatus(HttpStatus.CREATED)
public @ResponseBody String printPost(@RequestBody PrinterPostRequest printerPostRequest,
        HttpServletRequest request) {  
    HttpRequestLogger.log(request);
    return "OK";
}

Still, он не принимает запрос POST от принтера.Он принимает запрос Почтальона и успешно направляет тело запроса json в классы.

--- ДОБАВЛЕННАЯ ИНФОРМАЦИЯ НИЖЕ 2019-06-05 @ 10: 16 cet --- У меня была идея.Используя Spring RestTemplate, я отправил запрос POST приложению Boot с теми же заголовками и той же полезной нагрузкой, что и запрос, отправленный принтером.Я получаю исключение org.springframework.web.client.ResourceAccessException с этим сообщением:

I/O error on POST request for "https://boot.[my-domain].com:8443/cloudprint":sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Ответы [ 4 ]

4 голосов
/ 31 мая 2019

Если вы используете Spring Boot 2 , то это может произойти из-за csrf-protection. Он влияет только на запросы без GET, и по умолчанию он включен на в Spring Boot 2, но в более ранних версиях он отключен.

Так что это довольно хорошо отражает ваше описание проблемы - хотя я не до конца понимаю, как это может работать через Почтальон ... однако есть вероятность, что он каким-то образом обрабатывает это автоматически ...

В любом случае стоит попробовать:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
  }
}
3 голосов
/ 05 июня 2019

Привет, вы получаете доступ к службе REST через HTTPS.Сообщение, полученное с сервера, очень четкое.

sun.security.validator.ValidatorException: сбой при построении пути PKIX: sun.security.provider.certpath.SunCertPathBuilderException: невозможно найти действительный путь сертификациина запрошенную цель;вложенное исключение - javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: сбой построения пути PKIX: sun.security.provider.certpath.SunCertPathBuilderException: невозможно найти действительный путь сертификации для запрошенной цели

Вы не добавили сертификат в ваш магазин.Подробное пошаговое руководство о том, как это сделать, доступно здесь

Получение ssl.SSLHandshakeException при использовании клиента REST с заголовком, но прекрасно работает с PostMan

1 голос
/ 10 июня 2019

Я не уверен, какой формат при отправке запроса.Вы можете использовать почтальона, чтобы проверить, какой тип сообщения может обрабатывать ваше приложение.И отправьте такой же почтовый запрос, я полагаю, вы легко найдете образец кода для каждого из них.Обычно, когда мы отправляем сообщение со страницы html, мы используем x-www-form-urlencoded.

post methods from post man

1 голос
/ 08 июня 2019

Всякий раз, когда Java пытается подключиться к другому приложению по протоколу SSL (например, HTTPS, IMAPS, LDAPS), оно сможет подключиться к этому приложению только в том случае, если оно сможет ему доверять.

В мире Java доверие обрабатывается так: у вас есть хранилище ключей (обычно $ JAVA_HOME / lib / security / cacerts), также известное как хранилище доверенных сертификатов.Он содержит список всех известных сертификатов Центра сертификации (ЦС), и Java будет доверять только тем сертификатам, которые подписаны одним из тех ЦС или общедоступными сертификатами, которые существуют в этом хранилище ключей.

Эта проблема, следовательно, вызвана либо сертификатом, который является самоподписанным (ЦС не подписал его), либо цепочкой сертификатов, которая не существует в хранилище доверенных сертификатов Java.Он не доверяет сертификату и не может подключиться к приложению.

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