Dropwizard 解压缩请求过滤器
Dropwizard decompress request filter
我有一个 dropwizard 应用程序,其中客户端请求正文内容是 gzip 压缩后的内容。我需要解压 dropwizard 应用程序中的内容。我有以下代码,但在 GZIPInputStream is = new GZIPInputStream(new ByteArrayInputStream(gzipBody))
行出现异常 java.io.EOFException
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.util.zip.GZIPInputStream;
import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
@Path("/")
public class UserEventResource {
@POST
@Path("/save")
@Produces("application/json;charset=utf-8")
public Response save(byte[] gzipBody) {
try {
try (GZIPInputStream is = new GZIPInputStream(new ByteArrayInputStream(gzipBody))) {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
String body = new String(os.toByteArray(), Charset.forName("UTF-8"));
}
}
return Response.status(OK).build();
} catch (Exception exception) {
return Response.status(INTERNAL_SERVER_ERROR).build();
}
}
}
客户端正在发送以下请求,
curl -XPOST -d @test.gz http://localhost:8080/save
test.gz 是通过以下步骤创建的,
echo "hello world" > test
gzip test
代码本身有效。这个问题的问题是 cURL 请求。如果您添加 -v
(详细)标志,您就会看到问题。
$ curl -XPOST -v -d @test.gz http://localhost:8080/api/gzip/save
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /api/gzip/save HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 8
> Content-Type: application/x-www-form-urlencoded
问题出在最后一行:Content-Type
是 application/x-www-form-urlencoded
。不仅如此,文件中的数据也不会发送。具体我不知道,但它与 -d
标志有关。 cURL 的默认设置是在使用 -d
标志时发送 application/x-www-form-urlencoded
数据。
我们应该做的是使用 --data-binary
选项而不是 -d
并将 Content-Type
设置为 application/octet-stream
。这也会导致在服务器端调用正确的提供程序。
curl -XPOST -v \
-H 'Content-Type:application/octet-stream' \
--data-binary @test.gz \
http://localhost:8080/api/gzip/save
并且为了确保我们的端点只接受 application/octet-stream
,我们应该添加 @Consumes
注释。这很重要,因为我们不希望调用随机提供程序,这可能会导致出现奇怪的错误消息。
@POST
@Path("/save")
@Produces("application/json;charset=utf-8")
@Consumes("application/octet-stream")
public Response save(byte[] gzipBody) {
}
旁白
我不会为该方法使用 byte[]
参数。您真的不希望将整个文件读入内存。当然,示例已经读取它以获取字符串。但很可能在实际应用程序中,您要将文件保存在某个地方。因此,不用 byte[]
参数,只需使用 InputStream
。您可以将 InputStream
传递给 GZIPInputStream
构造函数。
对于上传文件,请考虑改用 multipart。使用 multipart,您不仅可以一次发送多个文件,还可以向文件添加元数据。请参阅 Jersey support and Dropwizard support(这不仅仅是 Jersey 功能的捆绑包装器。
我有一个 dropwizard 应用程序,其中客户端请求正文内容是 gzip 压缩后的内容。我需要解压 dropwizard 应用程序中的内容。我有以下代码,但在 GZIPInputStream is = new GZIPInputStream(new ByteArrayInputStream(gzipBody))
java.io.EOFException
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.util.zip.GZIPInputStream;
import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
@Path("/")
public class UserEventResource {
@POST
@Path("/save")
@Produces("application/json;charset=utf-8")
public Response save(byte[] gzipBody) {
try {
try (GZIPInputStream is = new GZIPInputStream(new ByteArrayInputStream(gzipBody))) {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
String body = new String(os.toByteArray(), Charset.forName("UTF-8"));
}
}
return Response.status(OK).build();
} catch (Exception exception) {
return Response.status(INTERNAL_SERVER_ERROR).build();
}
}
}
客户端正在发送以下请求,
curl -XPOST -d @test.gz http://localhost:8080/save
test.gz 是通过以下步骤创建的,
echo "hello world" > test
gzip test
代码本身有效。这个问题的问题是 cURL 请求。如果您添加 -v
(详细)标志,您就会看到问题。
$ curl -XPOST -v -d @test.gz http://localhost:8080/api/gzip/save
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /api/gzip/save HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 8
> Content-Type: application/x-www-form-urlencoded
问题出在最后一行:Content-Type
是 application/x-www-form-urlencoded
。不仅如此,文件中的数据也不会发送。具体我不知道,但它与 -d
标志有关。 cURL 的默认设置是在使用 -d
标志时发送 application/x-www-form-urlencoded
数据。
我们应该做的是使用 --data-binary
选项而不是 -d
并将 Content-Type
设置为 application/octet-stream
。这也会导致在服务器端调用正确的提供程序。
curl -XPOST -v \
-H 'Content-Type:application/octet-stream' \
--data-binary @test.gz \
http://localhost:8080/api/gzip/save
并且为了确保我们的端点只接受 application/octet-stream
,我们应该添加 @Consumes
注释。这很重要,因为我们不希望调用随机提供程序,这可能会导致出现奇怪的错误消息。
@POST
@Path("/save")
@Produces("application/json;charset=utf-8")
@Consumes("application/octet-stream")
public Response save(byte[] gzipBody) {
}
旁白
我不会为该方法使用
byte[]
参数。您真的不希望将整个文件读入内存。当然,示例已经读取它以获取字符串。但很可能在实际应用程序中,您要将文件保存在某个地方。因此,不用byte[]
参数,只需使用InputStream
。您可以将InputStream
传递给GZIPInputStream
构造函数。对于上传文件,请考虑改用 multipart。使用 multipart,您不仅可以一次发送多个文件,还可以向文件添加元数据。请参阅 Jersey support and Dropwizard support(这不仅仅是 Jersey 功能的捆绑包装器。