Play: How to prevent 404 on image src on first request after upload

我只是一个虾纸丫 提交于 2019-12-11 06:58:42

问题


I've got a simple form with 2 text and 1 file input

@helper.form(action = routes.CharactersController.newCharacter(), 'enctype -> "multipart/form-data") {
    @helper.inputText(field = characterForm("characterName"))
    @helper.inputText(field = characterForm("characterRealName"))
    @helper.inputFile(field = characterForm("characterImage"))

    <p>
        <input type="submit">
    </p>
}

in the newCharacter action I move the file to the asset folder.

Http.MultipartFormData body = request().body().asMultipartFormData();
Http.MultipartFormData.FilePart<File> picture = body.getFile("characterImage");
File file = picture.getFile();
file.renameTo(new File(LinkUtil.getCharacterUploadPath(), imageName + ".jpg"));

and then make a redirect to the /show page to display the new entered character

return redirect(routes.CharactersController.show(character.id, OrderType.MAIN.name()));

On the newly loaded page I only get a broken image and see a 404 in the console for the image. When I reload the page the image is rendered as expected.

So which part isn't ready when I redirect? Is it the renameTo or does play need some time to find the new asset? And how can I ensure everything is ready before I redirect?

Edit: To improve my question

I'm using play 2.5

LinkUtil.getCharacterUploadPath() resolves to "public/images/characters/"

I'm embedding the image in my show template like this:

<img src="@character.getImagePath">

which then resolves to "/assets/images/characters/imagename.jpg"

Edit 2: Further investigations:

When I check the filesystem within the newCharacter action with something like file.exists() for the new path, I get true. So the rename/moving part seems finished. However if I try to get the resource via environment

environment.getResource("relativePathToFile");

it's null. Even within a while loop the resource stays null. Which seems to indicate that the file isn't really added to the classpath yet. Unfortunately no matter how long I stay in the action the resource is always null. But when I put the Thread to sleep for 2000ms and then check the resource again in the show action it gets resolved properly. But only if I wait for 2s.

Another test was to utilize a onerror="window.location.reload()" on the image. Which results in about 5-10 reloads before the image is found.

So it's definetely a matter of time, but putting the Thread to sleep for an arbitrary amount feels plain wrong. There has to be a way to be sure that the file is available on the classpath.

Every hint/idea is appreciated.


回答1:


I got it to work! First my approach above was flawed.

Taking uploaded images, putting them into the public folder and trying to serve them with the AssetController won't work on a production build. Everything in the public folder is packaged into a .jar file. And some quick test hinted that my renameTo from above won't put the images where I expected them to be.

So here my solution:

Define a new route:

GET     /files/*file    controllers.Images.serve(file)

In the action use an absolute path on the filesystem

public class Images extends Controller {
    public Result serve(String file) {
        return ok(new java.io.File("/var/www/files/" + file));
    }
}

Access the file with something like this

<img src="/files/images/characters/imagename.jpg">

The Image is accessible instantly on the redirect request.

My guess about the delay in the Question is, that play tries to compile everything that is added to the classpath before making it accessible



来源:https://stackoverflow.com/questions/39425545/play-how-to-prevent-404-on-image-src-on-first-request-after-upload

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!