Jersey FormDataParam fails with 400 Bad Request

huangapple go评论74阅读模式
英文:

Jersey FormDataParam fails with 400 Bad Request

问题

Jersey 和 FormDataParam 在尝试上传图像到我的服务时表现得非常奇怪。我的服务运行在 Dropwizard 上。

接受图像(以及元数据对象)的方法如下:

@POST
@Path("/photos")
@Consumes("multipart/form-data")
fun upload(
    @FormDataParam("photo") fileInputStream: FileInputStream,
    @FormDataParam("metadata") metadata: PhotoMetadataV1RequestModel
) {
    // do something
}

我在 Guice 模块中注册了 MultipartFeature

public class JerseyModule extends AbstractModule {

    @Override
    protected void configure() {
        // 其他内容

        bind(MultiPartFeature.class).in(Scopes.SINGLETON);
    }

}

我在 build.gradle 中添加了 jersey-multipart 依赖项。

// Jersey
compile "org.glassfish.jersey.core:jersey-server:$jerseyVersion"
compile "org.glassfish.jersey.media:jersey-media-multipart:$jerseyVersion"

现在来看有趣的部分。

如果我尝试使用绝对路径上传文件,这实际上是有效的!但是,如果我尝试使用相对路径上传文件,它就无效

更重要的是,当服务部署在另一台机器上时(不是上传图像请求发出的同一台机器),它也无效。这很重要,因为我将我的服务部署到 Heroku,并且需要从其他地方上传图像!

这是有效的示例photo 使用绝对路径):

curl --location --request POST "http://localhost:8095/rest/v1/self/photos" \
--header "Authorization: Bearer GaKC8xQju5h" \
--form 'photo=/Users/whizzil/Desktop/nova_scripts/create_users/user-lina/photos-webp/photo-profile-1.webp' \
--form 'metadata={"photoType": "PROFILE", "position": 2};type=application/json'

然而,即使使用这个示例,如果服务器的 URL 不是 localhost,而是 Heroku 服务器等,它仍然无效

这是无效的示例photo 使用相对路径):

curl --location --request POST "http://localhost:8095/rest/v1/self/photos" \
--header "Authorization: Bearer GaKC8xQju5h" \
--form 'photo=@./photo-profile-1.webp' \
--form 'metadata={"photoType": "PROFILE", "position": 2};type=application/json'

当它不起作用时抛出的异常:

org.glassfish.jersey.internal.inject.ExtractorException: org.glassfish.jersey.internal.inject.ExtractorException: java.io.FileNotFoundException: Invalid file path
org.glassfish.jersey.media.multipart.FormDataParamException: HTTP 400 Bad Request
    at org.glassfish.jersey.media.multipart.internal.FormDataParamValueFactoryProvider$FormDataParamValueFactory.provide(FormDataParamValueFactoryProvider.java:352)
    at org.glassfish.jersey.server.spi.internal.ParamValueFactoryWithSource.provide(ParamValueFactoryWithSource.java:71)
    at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:90)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:127)

我感到很困惑。我尝试了谷歌搜索的一切,但没有成功。非常感谢任何帮助!

英文:

I have a very weird behaviour from Jersey and FormDataParam when trying to upload an image to my service. My service runs on Dropwizard.

The method that accepts an image (along with metadata object) looks like this:

    @POST
    @Path("/photos")
    @Consumes("multipart/form-data")
    fun upload(
        @FormDataParam("photo") fileInputStream: FileInputStream,
        @FormDataParam("metadata") metadata: PhotoMetadataV1RequestModel
    ) {
        // do something
    }

I've registered MultipartFeature in the Guice module.

public class JerseyModule extends AbstractModule {

	@Override
	protected void configure() {
        // other stuff

		bind(MultiPartFeature.class).in(Scopes.SINGLETON);
	}

}

I've added a jersey-multipart dependency in the build.gradle.

    // Jersey
    compile "org.glassfish.jersey.core:jersey-server:$jerseyVersion"
    compile "org.glassfish.jersey.media:jersey-media-multipart:$jerseyVersion"

Now the funny part.

This actually works if I try to upload a file using an absolute path! BUT, it does NOT work I try to upload a file using a relative path.

More importantly, it also does NOT work when a service is deployed on another machine (not the same the upload image request is coming from). This is important, because I deploy my service to Heroku, and I need to upload images from other places!

This is what works (absolute path for the photo):

curl --location --request POST "http://localhost:8095/rest/v1/self/photos" \
--header "Authorization: Bearer GaKC8xQju5h" \
--form 'photo=/Users/whizzil/Desktop/nova_scripts/create_users/user-lina/photos-webp/photo-profile-1.webp' \
--form 'metadata={"photoType": "PROFILE", "position": 2};type=application/json' 

However, even this does NOT work if the url of the server is not localhost, but e.g. Heroku server.

This is what does NOT work (relative path for the photo):

curl --location --request POST "http://localhost:8095/rest/v1/self/photos" \
--header "Authorization: Bearer GaKC8xQju5h" \
--form 'photo=@./photo-profile-1.webp' \
--form 'metadata={"photoType": "PROFILE", "position": 2};type=application/json'

The exception that is thrown when it doesn't work:

org.glassfish.jersey.internal.inject.ExtractorException: org.glassfish.jersey.internal.inject.ExtractorException: java.io.FileNotFoundException: Invalid file path
org.glassfish.jersey.media.multipart.FormDataParamException: HTTP 400 Bad Request
	at org.glassfish.jersey.media.multipart.internal.FormDataParamValueFactoryProvider$FormDataParamValueFactory.provide(FormDataParamValueFactoryProvider.java:352)
	at org.glassfish.jersey.server.spi.internal.ParamValueFactoryWithSource.provide(ParamValueFactoryWithSource.java:71)
	at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:90)
	at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:127)

I am lost here. I tried googling everything, but no success. Any help much appreciated!

答案1

得分: 1

Changing FileInputStream to InputStream solved the issue. I have no idea why, though.

英文:

Changing FileInputStream to InputStream solved the issue. I have no idea why, though.

huangapple
  • 本文由 发表于 2020年9月10日 01:31:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/63816707.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定