Как использовать перехватчики из Джерси, чтобы получить тело запроса
Я использую REST-Jersey
в своем проекте. Все данные POST отправляются в формате JSON
и не сортируются на стороне сервера в соответствующий beans. Что-то вроде этого:
Отправка запроса на сервер:
$('a#sayHelloPost').click(function(event){
event.preventDefault();
var mangaData = {
title:'Bleach',
author:'Kubo Tite'
}
var formData=JSON.stringify(mangaData);
console.log(formData);
$.ajax({
url:'rest/cred/sayposthello',
type: 'POST',
data: formData,
dataType: 'json',
contentType:'application/json'
})
});
Полезная нагрузка:
{"title":"Bleach","author":"Kubo Tite"}
Серверные конец:
@POST
@Path("/sayposthello")
@Produces(MediaType.APPLICATION_JSON)
public Response sayPostHello(MangaBean mb){
System.out.println(mb);
return Response.status(200).build();
}
MangaBean:
public class MangaBean {
private String title;
private String author;
@Override
public String toString() {
return "MangaBean [title=" + title + ", author=" + author + "]";
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
Выход на консоли:
MangaBean [title=Bleach, author=Kubo Tite]
Я получил реализацию REST-перехватчика от здесь.
public class JerseyFilter implements ContainerRequestFilter{
@Override
public ContainerRequest filter(ContainerRequest req) {
return req;
}
}
Я хочу получить доступ к полезной нагрузке (тело запроса) в перехватчике. Поскольку данные находятся в формате JSON, он недоступен в качестве параметров запроса. Есть ли способ получить тело запроса в методе перехватчика? Пожалуйста, совет.
Ответы
Ответ 1
Вот один из способов, который вы можете реализовать, очень похоже на то, как Джерси использует свои фильтры регистрации. Вы можете прочитать объект и вставить его обратно в запрос, чтобы вы случайно не использовали его в своем фильтре.
import com.sun.jersey.api.container.ContainerException;
import com.sun.jersey.core.util.ReaderWriter;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class JerseyFilter implements ContainerRequestFilter {
@Override
public ContainerRequest filter(ContainerRequest request) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = request.getEntityInputStream();
final StringBuilder b = new StringBuilder();
try {
if (in.available() > 0) {
ReaderWriter.writeTo(in, out);
byte[] requestEntity = out.toByteArray();
printEntity(b, requestEntity);
request.setEntityInputStream(new ByteArrayInputStream(requestEntity));
}
return request;
} catch (IOException ex) {
throw new ContainerException(ex);
}
}
private void printEntity(StringBuilder b, byte[] entity) throws IOException {
if (entity.length == 0)
return;
b.append(new String(entity)).append("\n");
System.out.println("#### Intercepted Entity ####");
System.out.println(b.toString());
}
}
Ответ 2
Вы можете получить тело POST из входного потока запросов.
Попробуйте что-то вроде этого:
@Override
public ContainerRequest filter(ContainerRequest req) {
try{
StringWriter writer = new StringWriter();
IOUtils.copy(req.getEntityInputStream(), writer, "UTF-8");
//This is your POST Body as String
String body = writer.toString();
}
catch (IOException e) {}
return req; }
Ответ 3
Вы можете читать содержимое только один раз, потому что это поток ввода. Если вы заберете его в перехватчике, вы не сможете его предоставить в основном анализе.
Что вам нужно сделать, так это создать фильтр, который читает данные и сделает его доступным для всех, кто в этом нуждается. Основные шаги:
- в вашем фильтре создайте новый подкласс HttpServletRequestWrapper, который считывает входные данные в буфер и переопределяет getInputStream(), чтобы предоставить новый входной поток в этот буфер
- передать новый подкласс вниз по цепочке
Ответ 4
Не используйте метод in.available()
для проверки всех байтов входного потока. Некоторые клиенты не устанавливают это значение. И в этом случае это будет неприятным, если поток ввода тела сообщения существует.
InputStream in = request.getEntityInputStream();
final StringBuilder b = new StringBuilder();
try {
if (in.available() > 0)
Используйте ниже код
String json = IOUtils.toString(requestContext.getEntityStream(), Charsets.UTF_8);
messageBody = json;
InputStream in = IOUtils.toInputStream(json);
requestContext.setEntityStream(in);