【发布时间】:2019-10-17 06:36:07
【问题描述】:
我正在使用具有云功能的收据打印机。它与我正在实施的服务器规范进行通信。它每隔 x 秒轮询一个带有 POST 请求的 URL,当 POST 响应包含某条信息时,打印机会向该 URL 发送一个 GET 请求以获取要打印的信息。
我正在将打印服务器实现为 Spring Boot 服务器,我在使用 POST 方法时遇到了一些奇怪的问题,我需要一些帮助。
我的问题是从打印机到服务器的 POST 请求永远不会到达控制器。但是,我可以从 Postman 向完全相同的 URL 发送 POST 请求,并由控制器处理。
网址很简单:https://www.[my-domain].com:[port-number]/cloudprint
另外,我尝试将控制器方法复制到另一个 Spring(不是 Boot)应用程序,在 Apache 后面的 Tomcat 实例上运行,并且在那里,来自打印机的 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 下方添加信息--- 由于我有一个接受来自打印机的 POST 请求的常规 Spring(非引导)应用程序,因此我能够在传入请求中记录信息。所以我就这么做了。
这是来自打印机的 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
这是从 Postman 到完全相同的 URL 的 POST 请求之一,它被 Spring boot 控制程序接受:
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. content-length header 不同。 3. Postman 请求具有来自云打印机的请求所没有的三个标头。它们是:cache-control、Postman-token 和accept-encoding
---在 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}}]}
我创建了相应的类,并将Boot应用程序中的POST方法改成这样:
@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";
}
仍然没有从打印机接收 POST 请求。它接收 Postman 请求并成功将请求正文 json 编组到类中。
---在 2019-06-05 @10:16 cet 下方添加信息--- 我有个主意。使用 Spring RestTemplate,我向 Boot 应用程序发送了一个 POST 请求,其标题和有效负载与打印机发送的请求相同。我收到一条带有此消息的 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
【问题讨论】:
-
首先在本地运行你的应用,如果端口是8080,然后尝试使用localhost:8080/cloudprint进行post调用并检查
-
在 DEBUG 模式下,日志通常会打印出侦听器正在处理的 URL 端点。您可能想从那里开始。
-
检查打印机的代理/防火墙配置。
-
@sambit: 我将无法让打印机调用 localhost
-
@MatsAndersson 你有一个有效的 SSL 证书还是自签名的? Spring Boot 会终止 SSL 还是有前端代理?
标签: java spring rest spring-boot security