Pobieranie plików z nazwami bez krzaków

Ostatnio w pracy toczę boje z serwisami REST i przy okazji tworzenia serwisu do upload‚u i download‚u plików natrafiłem na ciekawy, dawno temu utworzony przeze mnie zlepek kodu. Jako że czasami moja dawna twórczość mnie zachwyca, poniżej ten fragment zacytuję :)

public String encodeFilename(String filename, String userAgent) throws UnsupportedEncodingException {
  if (userAgent.contains("MSIE") || userAgent.contains("Opera")) {
    return URLEncoder.encode(filename, "UTF-8").replace("+", "%20");
  } else {
    return "=?UTF-8?B?" + new String(Base64.encodeBase64(filename.getBytes("UTF-8"))) + "?=";
  }
}

No i po co to komu? Ano po to, aby nadać pobieranemu plikowi nazwę z naszymi rodzimymi krzaczkami. Nie będę się zagłębiał w to, czemu tak jest, wystarczy wiedzieć, że prawie wszystkie przeglądarki nie odczytają poprawnie nazwy pliku przekazanej poprzez parametr nagłówka Content-Disposition. Co więcej, różnym przeglądarkom trzeba serwować zakodowaną nazwę pliku w nieco inny sposób.

Dla różnych wersji IE i Opery wystarczy zrobić URLEncoder.encode(filename, "UTF-8"). Dodatkowo trzeba zamienić plusy na kody spacji, inaczej zamiast spacji w nazwach plików będziemy mieli znaki „+”. Pozostałe przeglądarki wymagają specjalnie spreparowanego kodu, który informuje, że nazwa pliku została zakodowana w formacie UTF-8.

Powyższy kod sprawdzał się przez około 3 lata na różnych wersjach przeglądarek IE, Firefox, Chrome i Opera, więc pewnie podziała jeszcze trochę. Jako mały bonus, poniżej fragment serwisu REST obsługującego download plików:

@GET
@Path("/{id}")
public Response download(@PathParam("id") Long id, @HeaderParam("user-agent") String userAgent) {
  try {
    Attachment a = am.read(id);
    if (a == null) {
      String msg = "File not found for ID: " + id;
      return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
    }

    InputStream is = am.readAsStream(a);

    String contentType = URLConnection.guessContentTypeFromStream(is);
    if (contentType == null) {
      contentType = MediaType.APPLICATION_OCTET_STREAM;
    }

    String encodedFileName = encodeFilename(a.getFullName(), userAgent);

    return Response.ok(is, contentType).header("Content-Disposition", "filename=\"" + encodedFileName + "\"").build();
  } catch (Throwable e) {
    LOG.error("Coult not download file", e);
    return Response.serverError().entity(e.getMessage()).build();
  }
}
Skomentuj

5 Komentarze.

  1. W kontekście zamieszczonego w twoim poście kawałka kodu możesz zainteresować się poniższym : http://www.refactoring.com/catalog/extractMethod.html

  2. Bardzo ciekawy artykuł – właściwie nie trzeba nic dodawać.
    A tak w ogóle to gratuluję ciekawej strony!
    Wojtek ostatnio napisał(a)… Forum o kawie z cukrem

  3. Witam kolegę
    Mam prośbę o pomoc. W jednej z moich instalacji wordpressa używam motywy zbench tak jak ty.
    Od pewnego czasu linterka „ł” pojawia się jako „?”
    Jak to naprawić?

Skomentuj


UWAGA - Możesz używać HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

CommentLuv badge