【发布时间】:2013-08-09 01:32:35
【问题描述】:
我正在尝试在请求过滤器中获取请求的表单参数:
@Override
public ContainerRequest filter(final ContainerRequest request) {
final Form formParameters = request.getFormParameters();
//logic
return request;
}
但是,表单似乎总是为空。 HttpRequestContext.getFormParameters() 文档说:
获取请求实体的表单参数。
此方法将确保请求实体被缓冲,以便应用程序可以使用它。
返回: 表单参数,如果有请求实体且内容类型为“application/x-www-form-urlencoded”,则返回不包含参数的实例。
我的资源使用 @Consumes("application/x-www-form-urlencoded") 进行了注释,尽管它在请求过滤器之后才会被匹配 - 这就是为什么这不起作用吗?
我尝试进行一些研究,但找不到任何确凿证据证明这是否可行。有this 4-year old discussion,其中 Paul Sandoz 说:
如果您使用 Jersey 过滤器或使用
HttpRequestContext,您可以获得如下表单参数:[到 Jersey 1.1.1HttpRequestContext.getFormParameters的链接断开]
我还发现了 this 3-year-old discussion 关于如何在请求过滤器中获取 multipart/form-data 表单字段的信息。在其中,Paul Sandoz 使用了以下代码:
// Buffer
InputStream in = request.getEntityInputStream();
if (in.getClass() != ByteArrayInputStream.class) {
// Buffer input
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ReaderWriter.writeTo(in, baos);
} catch (IOException ex) {
throw new ContainerException(ex);
}
in = new ByteArrayInputStream(baos.toByteArray());
request.setEntityInputStream(in);
}
// Read entity
FormDataMultiPart multiPart = request.getEntity(FormDataMultiPart.class);
我尝试为Form 模拟这种方法,但request.getEntityInputStream() 的结果始终是一个空流。看看the source of getFormParameters,这个方法实际上已经在做同样的事情了:
@Override
public Form getFormParameters() {
if (MediaTypes.typeEquals(MediaType.APPLICATION_FORM_URLENCODED_TYPE, getMediaType())) {
InputStream in = getEntityInputStream();
if (in.getClass() != ByteArrayInputStream.class) {
// Buffer input
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
ReaderWriter.writeTo(in, byteArrayOutputStream);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
in = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
setEntityInputStream(in);
}
ByteArrayInputStream byteArrayInputStream = (ByteArrayInputStream) in;
Form f = getEntity(Form.class);
byteArrayInputStream.reset();
return f;
} else {
return new Form();
}
}
在我了解实体输入流之前,我无法弄清楚是什么在消耗实体输入流。 Jersey 中的某些东西一定在消耗它,因为表单参数稍后会传递到资源方法中。我在这里做错了什么,或者这是不可能的(为什么)?
编辑:以下是发送请求的示例:
POST /test/post-stuff HTTP/1.1
Host: local.my.application.com:8443
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
form_param_1=foo&form_param_2=bar
这是(有点多余的)request logging:
INFO: 1 * Server in-bound request
1 > POST https://local.my.application.com:8443/test/post-stuff
1 > host: local.my.application.com:8443
1 > connection: keep-alive
1 > content-length: 33
1 > cache-control: no-cache
1 > origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
1 > user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
1 > content-type: application/x-www-form-urlencoded
1 > accept: */*
1 > accept-encoding: gzip,deflate,sdch
1 > accept-language: en-US,en;q=0.8
1 > cookie: [omitted]
1 >
这是该请求的响应标头,包括Jersey Trace:
Content-Type →application/json;charset=UTF-8
Date →Fri, 09 Aug 2013 18:00:17 GMT
Location →https://local.my.application.com:8443/test/post-stuff/
Server →Apache-Coyote/1.1
Transfer-Encoding →chunked
X-Jersey-Trace-000 →accept root resource classes: "/post-stuff"
X-Jersey-Trace-001 →match path "/post-stuff" -> "/post\-stuff(/.*)?", [...], "(/.*)?"
X-Jersey-Trace-002 →accept right hand path java.util.regex.Matcher[pattern=/post\-stuff(/.*)? region=0,11 lastmatch=/post-stuff]: "/post-stuff" -> "/post-stuff" : ""
X-Jersey-Trace-003 →accept resource: "post-stuff" -> @Path("/post-stuff") com.application.my.jersey.resource.TestResource@7612e9d2
X-Jersey-Trace-004 →match path "" -> ""
X-Jersey-Trace-005 →accept resource methods: "post-stuff", POST -> com.application.my.jersey.resource.TestResource@7612e9d2
X-Jersey-Trace-006 →matched resource method: public javax.ws.rs.core.Response com.application.my.jersey.resource.TestResource.execute(java.lang.String,java.lang.String)
X-Jersey-Trace-007 →matched message body reader: class com.sun.jersey.api.representation.Form, "application/x-www-form-urlencoded" -> com.sun.jersey.core.impl.provider.entity.FormProvider@b98df1f
X-Jersey-Trace-008 →matched message body writer: java.lang.String@f62, "application/json" -> com.sun.jersey.core.impl.provider.entity.StringProvider@1c5ddffa
这是(不起眼的)servlet 配置:
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.application.my.jersey</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
<param-value>com.application.my.jersey.MyFilterFactory</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.feature.Trace</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
这是示例资源:
@Path("/post-stuff")
@Produces(MediaType.APPLICATION_JSON)
public final class TestResource {
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response execute(
@FormParam("form_param_1") final String formParam1,
@FormParam("form_param_2") final String formParam2
) {
return Response.created(URI.create("/")).entity("{}").build();
}
}
我使用的是 Jersey 1.17。
对于那些感兴趣的人,我正在尝试推出自己的必需参数验证,如JERSEY-351 中所述。我的解决方案 here 适用于查询、cookie 和标头参数 - 表单参数对我不利。
【问题讨论】:
-
您能否向我们展示您发送到其余端点的请求。
-
@michal.gajdos 看看我的编辑,让我知道我还能提供什么。
-
formParam1和formParam2在您的资源方法中也是null吗?只是为了确保MyFilterFactory包含您的第一个 sn-p 中的#filter方法? -
@michal.gajdos
formParam1和formParam1按预期传递到资源方法(不是null)。是的,MyFilterFactory创建了资源过滤器,该过滤器创建了具有filter实现的容器请求过滤器。
标签: java jersey http-post http-request jersey-1.0