Я работаю с чековым принтером с облачной функцией.Он связывается со спецификацией сервера, которую я реализую.Он опрашивает 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