У меня есть приложение для создания запросов сертификатов сервера, как если бы вы использовали java keytool или что-то в этом роде. Я пытаюсь вернуть созданный запрос сертификата и ключ в zip-файле, но, хоть убей, я не могу заставить свой REST-контроллер отвечать на HTTP-запрос. ИСПРАВЛЕНИЕ: контроллер отвечает, но код метода никогда не выполняется.
Сервер действительно получает запрос, потому что мой фильтр CORS выполняется. Но у меня есть отладка в методе контроллера, и она никогда не срабатывает. Подпись метода верна? Мне нужна еще пара глаз, пожалуйста?
Вот мой код контроллера:
@RequestMapping(method = RequestMethod.POST, value = "/generateCert/")
public ResponseEntity<InputStreamResource> generateCert(@RequestBody CertInfo certInfo) {
System.out.println("Received request to generate CSR...");
byte[] responseBytes = commonDataService.generateCsr(certInfo);
InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(responseBytes));
System.out.println("Generated CSR with length of " + responseBytes.length);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=certificate.zip")
.contentType(MediaType.parseMediaType("application/zip"))
.contentLength(responseBytes.length)
.body(resource);
}
А вот и запрос Angular:
generateCertificate(reqBody: GenerateCert) {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
this.http.post(this.urlGenerateCert, JSON.stringify(reqBody), {headers: headers}).subscribe(
(data) => {
let dataType = data.type;
let binaryData = [];
binaryData.push(data);
this.certBlob = new Blob(binaryData);
});
return this.certBlob;
}
И, наконец, заголовки запроса и ответа, которые я скопировал из сетевой панели:
Response
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type, Authorization, Accept, X-Requested-With, remember-me
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 3600
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Date: Thu, 27 Dec 2018 22:48:00 GMT
Expires: 0
Location: http://localhost:8102/login
Pragma: no-cache
Set-Cookie: JSESSIONID=EDACE17328628D579670AD0FB53A6F35; Path=/; HttpOnly
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Request
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 205
Content-Type: application/json
Host: localhost:8102
Origin: http://localhost:4200
Referer: http://localhost:4200/generateCerts
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36
Я действительно боролся с тем, чтобы CORS работал, так что, может быть, это мешает запросу? Я ненавижу публиковать весь этот код без крайней необходимости. У кого-нибудь есть идеи?
Умм, кажется, я подписался на запрос - пролистайте.
Вы подписывайтесь. Сразу после того, как вы подписались и, таким образом, отправили запрос, вы возвращаете this.certBlob, который не определен, поскольку он будет заполнен гораздо позже, после того, как метод вернется в течение длительного времени, когда обратный вызов передан на подписку был вызван, потому что наконец-то пришел ответ от сервера. Нельзя есть тост сразу после того, как вы положили его в тостер. Вам нужно подождать, пока тостер не сообщит, что тосты приготовлены на гриле.
Не могли бы вы вместо этого поделиться тем, что я должен делать? Разработка пользовательского интерфейса - не моя специальность.
Но имейте в виду, моя проблема в том, что серверная часть вообще не отвечает. Я еще даже не проверил файл.
Я тебе уже сказал. Прочтите мой первый комментарий. Служба должна возвращать abservable. Т.е. return this.http.post(...); Компонент, который вызывает службу te и хочет получить доступ к сертификату, должен подписаться на наблюдаемое, возвращаемое службой. НЕ подписывайтесь на сервис.
Если сервер вообще не отвечает, почему в вашем вопросе указано 2 ответа?
Я должен был быть более конкретным - мой метод контроллера не вызывается.
Тогда что именно происходит и каковы тогда ответы на ваш вопрос? Они вообще актуальны?
Вызывается фильтр сервлета, но запрос никогда не сопоставляется с методом контроллера. Подумал, может, с подписью что-то не так? И я неправильно набрал - это запрос и ответ, которые я получаю. Я подумал, что из них можно что-то почерпнуть.
Начать с открытия сетевой панели в инструментах разработчика вашего браузера? Какие запросы отправляются? Если вы используете CORS, вы должны иметь OPTIONS, за которым следует POST. Убедитесь, что POST есть. Проверьте URL. (Почему вы используете CORS, BTW, действительно ли вы планируете открыть этот API для внешних приложений JavaScript?)
Позвольте нам продолжить обсуждение в чате.
Нет, я не болтаю. Уточните пожалуйста свой вопрос.
Вопрос отредактирован!
Вы до сих пор не сказали, был ли отправлен запрос POST, и какой был URL-адрес запроса. Если запрос POST не отправляется, это означает, что ваша конфигурация CORS неверна. И вы до сих пор не сказали, почему вы используете CORS.
Вы аннотировали свой внутренний метод generateCert с помощью @CrossOrigin?
Я аннотировал класс, да.
Почему бы не использовать REST-клиент, например Почтальон, чтобы сначала проверить конечную точку. Это поможет точно узнать, связана ли проблема с приложением angular или приложением spring -boot.





определить proxy.conf.json
{
"/login*": {
"target":"http://localhost:8080",
"secure":false,
"logLevel":"debug"
}
}
теперь в твоем package.json
"scripts": {
"start":"ng serve --proxy-config proxy.config.json"
}
Я думаю, что есть проблема с подключением в обоих веб-приложениях. Попробуйте.
Когда Angular встречает это утверждение
this.http.post(url,body).subscribe(data => # some code
);
Он немедленно возвращается для выполнения остальной части кода, в то время как служба продолжает выполняться. Прямо как будущее на Java.
Здесь, если ты
return this.cert;
Вы не получите значение, которое в конечном итоге может быть заполнено службой this.http. Поскольку страница уже отрисована и код выполнен. Вы можете проверить это, включив это в Observable и вне его.
console.info(“Inside/outside observable” + new Date().toLocalTimeString());
В списке заголовков запроса / ответа отсутствует информация об URL-адресе, методе и наиболее важном коде статуса ответа.
Увидев Location: http://localhost:8102/login среди заголовков ответов, я могу предположить, что это может быть 401 Unauthorized или что-то еще, что перенаправляет на страницу входа. Следовательно, если в цепочке фильтров есть фильтр аутентификации, он может быть виновником.
Следующие заголовки запроса
Host: localhost:8102
Origin: http://localhost:4200
предполагает, что вы выполняете CORS, и фильтр CORS действительно может быть задействован и выполнить ответ до того, как запрос будет перенаправлен на контроллер. Я предлагаю установить точку останова в фильтре CORS (и в других фильтрах, если таковые имеются) и отладить ее до точки, в которой будет возвращен ответ.
Да, это именно то, что я сделал, и я обнаружил, что запрос поступает на сервер, но не на метод моего контроллера.
Спасибо всем, кто внес свой вклад. Я обнаружил, что ошибка связана с заголовками моего метода контроллера. После их изменения метод был вызван правильно. Вот что сработало:
@RequestMapping(method = RequestMethod.POST, path = "/generateCert",
produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE}, consumes = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<byte[]> generateCert(@RequestBody CertInfo certInfo) {
byte[] responseBytes = commonDataService.generateCsr(certInfo);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
.contentLength(responseBytes.length)
.body(responseBytes);
}
Это снова мы. http.post возвращает Observable <Blob>. Не клякса. Почему? Потому что AJAX асинхронный. Таким образом, он возвращает наблюдаемое, что позволяет вам получать уведомления намного позже, когда ответ будет наконец доступен. Когда вы запускаете
this.certBlob, вы делаете это сразу после отправки запроса. Ответ еще не пришел. Итак, this.certBlob не определен. Сервис должен возвращать наблюдаемое. Компонент, заинтересованный в ответе, должен подписаться на возвращаемый наблюдаемый объект, чтобы получить уведомление о возвращении сертификата.