クラウド機能のあるレシートプリンターを使っています。それは私が実装しているサーバー仕様と通信します。 POSTリクエストでx秒ごとにURLをポーリングし、POST応答に特定の情報が含まれている場合、プリンターはGETリクエストをURLは、印刷する情報を取得します。
プリントサーバーをSpring Bootサーバーとして実装していますが、POSTメソッドでいくつかの奇妙な問題が発生しています。
私の問題は、POSTプリンターからサーバーへの要求がコントローラーに届かないことです。しかし、POST Postmanからの要求を送信できます完全に同じURLに変更すると、コントローラーによって処理されます。
URLは単純です: https:// www。[my-domain] .com:[port-number]/cloudprint
また、Apacheの背後にあるTomcatインスタンスで実行されている別のSpring(ブートではない)アプリケーションにコントローラーメソッドをコピーしようとしましたが、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要求の1つです。これは、Springブートoontrollerによって受け入れられません。
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リクエストの1つです。これは、IS Springブートoontrollerによって受け入れられます:
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ヘッダーが異なります。 3. Postmanリクエストには、クラウドプリンターからのリクエストにはない3つのヘッダーがあります。それらは:キャッシュ制御、ポストマントークン、受け入れエンコード
---以下の追加情報2019-06-03 @ 17:56 cet ---わかりました。メッセージ本文をログに記録する方法を理解しました。これは、実際に303文字である適切にフォーマットされたjson構造です。
{"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を使用して、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
Spring Boot 2を使用する場合、csrf-protectionが原因で発生する可能性があります。これは非GETリクエストにのみ影響し、Spring Boot 2ではデフォルトでonになっていますが、以前のバージョンではオフになっています。
だから、それはあなたの問題の説明をかなりよく反映しています-私はそれがPostmanを介してどのように機能することができるか完全には理解していません...しかし、それが何らかの方法でそれを自動的に処理する可能性があります...
とにかくそれは試してみる価値があります:
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
こんにちは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:要求されたターゲットへの有効な証明書パスが見つかりません
証明書をcaストアに追加していません。これを行う方法の詳細なステップバイステップガイドは、こちらから入手できます。
RESTクライアントでヘッダーを使用する場合にssl.SSLHandshakeExceptionを取得しますが、PostMan で正常に動作します)
JavaがSSL(例:HTTPS、IMAPS、LDAPS)を介して別のアプリケーションに接続しようとする場合は常に、信頼できる場合にのみ、そのアプリケーションに接続できます。
Javaの世界で信頼を処理する方法は、トラストストアとも呼ばれるキーストア(通常は$ Java_HOME/lib/security/cacerts)があることです。これには、すべての既知の証明書のリストが含まれます権限(CA)証明書、およびJavaは、そのキーストア内に存在するこれらのCAまたは公開証明書のいずれかによって署名された証明書のみを信頼します。
したがって、この問題は、自己署名された証明書(CAが署名しなかった)またはJavaトラストストア内に存在しない証明書チェーンです。証明書を信頼していません。そして、アプリケーションへの接続に失敗します。