13

I am trying uploading an image with this javascript code:

var reader  = new FileReader();
reader.onloadend = function() {
  var bytes = window.btoa(reader.result);
  var ext = file.name.split(".").pop();
  xhr.send("bytes="+bytes+"&type="+ext);
}
reader.readAsBinaryString(file);

where bytes is passed to this java code on the server side:

public Integer upload(String bytes, String type) throws IOException {
    byte[] bytes_final = Base64.getDecoder().decode(bytes.split(",")[1]);
    BufferedImage src = ImageIO.read(new ByteArrayInputStream(bytes_final));
    ...
}

but I am getting the error:

java.lang.IllegalArgumentException: Illegal base64 character 20
    at java.base/java.util.Base64$Decoder.decode0(Base64.java:743) ~[na:na]
    at java.base/java.util.Base64$Decoder.decode(Base64.java:535) ~[na:na]
    at java.base/java.util.Base64$Decoder.decode(Base64.java:558) ~[na:na]
    at org.loja.model.imagem.ImagemService.upload(ImagemService.java:25) ~[classes/:1.0-SNAPSHOT]
    at org.loja.model.imagem.ImagemController.upload(ImagemController.java:25) ~[classes/:1.0-SNAPSHOT]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:891) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) ~[servlet-api.jar:na]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[servlet-api.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[catalina.jar:9.0.14]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-websocket.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[catalina.jar:9.0.14]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:158) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[catalina.jar:9.0.14]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[catalina.jar:9.0.14]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[catalina.jar:9.0.14]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[catalina.jar:9.0.14]
    at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:130) ~[spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
    at org.springframework.boot.web.servlet.support.ErrorPageFilter.access$000(ErrorPageFilter.java:66) ~[spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
    at org.springframework.boot.web.servlet.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:105) ~[spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:123) ~[spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[catalina.jar:9.0.14]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[catalina.jar:9.0.14]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[catalina.jar:9.0.14]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[catalina.jar:9.0.14]
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668) ~[catalina.jar:9.0.14]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[catalina.jar:9.0.14]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[catalina.jar:9.0.14]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) ~[tomcat-coyote.jar:9.0.14]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-coyote.jar:9.0.14]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) ~[tomcat-coyote.jar:9.0.14]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417) ~[tomcat-coyote.jar:9.0.14]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-coyote.jar:9.0.14]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-util.jar:9.0.14]
    at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

anyone can give me a hint of what's wrong here?

ps.:

complete javascript function:

function image_upload() {
  var file_input = this;
  var name = file_input.getAttribute("id");
  var url = file_input.dataset.url;

  for(var i = 0; i<this.files.length; i++) {
    var file =  this.files[i];
    var xhr = new XMLHttpRequest();
    xhr.open("POST", url, true);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var id = xhr.responseText;
            var input = createElement("input");
            input.setAttribute("type", "hidden");
            input.setAttribute("name", name);
            input.setAttribute("value", id);
            file_input.after(input);
        }
    };
    var reader  = new FileReader();
    reader.onloadend = function() {
      var bytes = reader.result;
      var ext = file.name.split(".").pop();
      xhr.send("bytes="+bytes+"&type="+ext);
    }
    reader.readAsDataURL(file);
  }
}

complete java function:

  public Integer upload(String bytes, String type) throws IOException {
    byte[] bytes_final = Base64.getDecoder().decode(bytes.split(",")[1]);
    BufferedImage src = ImageIO.read(new ByteArrayInputStream(bytes_final));

    String file_name = file_path + File.separator + fileName();
    File arquivo = new File(file_name);
        if(!arquivo.exists())
            if(arquivo.mkdirs())
                arquivo.createNewFile();

    ImageIO.write(src, type, arquivo);

    Imagem imagem = new Imagem();
    imagem.setFileName(file_name);
    this.dao.insert(imagem);

    return imagem.getId();
  }
Kleber Mota
  • 8,521
  • 31
  • 94
  • 188
  • 1
    Why are you doing `bytes.split(",")[1]`? Add what is the value of `bytes` and `type` when received in Java. – Karol Dowbecki Jan 13 '19 at 00:09
  • how do you know that your uploading files are base64 format? – duc mai Jan 13 '19 at 00:10
  • @KarolDowbecki the `split()` is done to separate the `data:image/png;base64` part from the rest od the data, like seen in this image: https://imgur.com/a/aO9PMBz (also include the value for `type`). – Kleber Mota Jan 13 '19 at 00:15
  • @ducmai It is what `reader.readAsDataURL(file);` sends to the server, at least according to what I read about it. – Kleber Mota Jan 13 '19 at 00:16
  • 1
    `x-www-form-urlencoded` sounds wrong (for binary data) ...and url- is *not* base encoded. – xerx593 Jan 13 '19 at 00:17
  • @xerx593 if I remove the `x-www-form-urlencoded`, the error changes to missing required parameter `bytes`. And what you mean about url is not encoded? url is currently set up to `/imagem/upload` mapped in my controller to receive POST requests with 2 parameters (bytes and type). Only bytes is Base64 encoded. – Kleber Mota Jan 13 '19 at 00:50
  • no, removing is not an option! :) (I thought about replacing with something more suitable...)...but the key point is, that your data leaves the client ["url encoded"](https://en.wikipedia.org/wiki/Percent-encoding) (whichever encoding the original data had) ... to restore the original data you have to "url decode" before (....you can base64-decode) – xerx593 Jan 13 '19 at 10:35
  • `application/octet-stream` would be "appropriate" (content type) for a "pure byte body", with `application/multipart` you can compose modular (multiple type) and more complex "bodies" (like email or fileupload ...or so..). – xerx593 Jan 21 '19 at 14:22

3 Answers3

14

Illegal base64 character 20 means that received value contained an invalid character not present in the Base64 alphabet. 20 is a space, because error message uses hex format. The data on your screenshot shows that there are spaces in the sent bytes value.

As per this answer you can use reader.readAsBinaryString and then btoa to convert file content to Base64 yourself.

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
  • This suppose to happen when `reader.readAsDataURL(file);` is called? Using `trim` or something is enough here? – Kleber Mota Jan 13 '19 at 00:21
  • @KleberMota I think not, I don't know why there are spaces on your screenshot. Can you confirm using Developer Console or `console.log` that there are spaces there? You can try `bytes.split(",")[1].replaceAll(" ", "")` to remove spaces in Java. – Karol Dowbecki Jan 13 '19 at 00:24
  • yes, there are spaces on the string. I already tried remove them in the javascript code (with `bytes.trim()`) and in the java code (with the way you described and with `bytes.split(",")[1].trim()`) and do not work. i think something is going wrong with the file reader process in the client side? – Kleber Mota Jan 13 '19 at 12:33
5

Your code is strange. Why are you not doing it this way?:

function image_upload() {
  var file_input = this;
  var name = file_input.getAttribute("id");
  var url = file_input.dataset.url;

  for(var i = 0; i<this.files.length; i++) {
    var file =  this.files[i];
    var xhr = new XMLHttpRequest();
    xhr.open("POST", url, true);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var id = xhr.responseText;
            var input = createElement("input");
            input.setAttribute("type", "hidden");
            input.setAttribute("name", name);
            input.setAttribute("value", id);
            file_input.after(input);
        }
    };
    var formData = new FormData();
    formData.append("image", file, name) 
    xhr.send(formData)
  }
}

??

And you don't need any base64

Or more modern, this variant:

   function image_upload() {
      let file_input = this;
      let name = file_input.getAttribute("id");
      let url = file_input.dataset.url;
      let uploads = Array.from(this.files).map((file) => {
        var formData  = new FormData();
        formData.append(name, file, file.name);
        return fetch(url, {method: 'POST', body: formData}).then((response) => response.text()).then((id)=>{  
               let input = document.createElement("input");
                input.setAttribute("type", "hidden");
                input.setAttribute("name", name);
                input.setAttribute("value", id);
                file_input.after(input);
          });
       });
       return uploads;
      }));
    }
Alex Nikulin
  • 8,194
  • 4
  • 35
  • 37
  • With the suggested code, I am getting the error "required parameter 'bytes' not present". I tried change `formData.append("image", file, name)` to `formData.append("bytes", file, name)` but i got the same error. Any idea how to fix that? – Kleber Mota Jan 18 '19 at 12:06
  • at client or server side? – Alex Nikulin Jan 18 '19 at 12:15
  • I am not sure. The client is not send the right parameter to the server, therefore the server is unable to execute the controller method which should handle this request from the client; – Kleber Mota Jan 18 '19 at 13:55
  • But I think the message is triggered by the server, but due some failure on client in build the right request. – Kleber Mota Jan 18 '19 at 13:57
  • You should server side controller definition, now you will receive file frim form, not base64. – Alex Nikulin Jan 18 '19 at 13:59
  • When you mentioned server side controller definition, what do you mean? Use MultipartFile class? – Kleber Mota Jan 19 '19 at 00:39
  • 1
    @KleberMota i mean change definition for receive file from form. You can see here https://stackoverflow.com/q/2422468/5138198 – Alex Nikulin Jan 19 '19 at 04:06
0

You can check working example of Base64 upload here and here

JS (sends a list of files in Base64 encoding)

<form id="jsonForm"
      class="form-inline"
      role="form">
        <input id="jsonFiles"
               width="400px"
               type="file"
               class="form-control-file border"
               name="file"
               accept="image/gif, image/jpeg, image/png"
               multiple>
        &nbsp;<button type="button" onclick="processJsonForm()" class="btn-sm btn-outline-primary">отправить</button>
</form>


function processJsonForm() {
  if (window.File && window.FileList && window.FileReader) {
    readJsonFiles(document.getElementById('jsonFiles').files, submitJsonForm);
  } else {
    alret("Your browser does not support File API");
  }
}

function readJsonFiles(files, callback) {
  var count = files.length;
  var result = [];
  for (i = 0; i < files.length; i++) {
    var file = files[i];
    var picReader = new FileReader();
    picReader.onload = (function(f) {
      return function(event) {
          var item = {};
          item.name   = f.name;
          item.type   = f.type;
          item.base64 = event.target.result;
          result.push(item);
          if (!--count) callback(result);
      }
    })(file);
    picReader.readAsDataURL(file);
  }
}

function submitJsonForm(data) {
  $.ajax({
     url: baseURL,
     type: 'POST',
     data: JSON.stringify(data),
     contentType: 'application/json; charset=UTF-8',
     crossDomain: true,
     headers: { 'Access-Control-Allow-Origin': '*' },
     success: function(data, status) {
       $.alert("Sent URLs to server<br>"  +
               "Response code: " + status + "<br>" +
               "Server response: " + data, {
         autoClose: true,
         closeTime: 10000,
         type: 'success',
         title: false,
       });
       // console.log(data);
     },
     error: function(data, status){
       $.alert(data, "error");
       // console.log(data);
     }
  });
}

Java controller


// here input arguments Base64EncodedImageJson have Base64 string in 'base64' field

    @PostMapping(path = "/upload", consumes = "application/json", produces = "application/json")
    public DeferredResult<Collection<ProcessingResult>> processJSON(@RequestBody Base64EncodedImageJson [] imagesEncoded) {
        logger.debug("processing application/json request");
        DeferredResult<Collection<ProcessingResult>> deferredResult = new DeferredResult<>();
        CompletableFuture.supplyAsync( () -> base64Uploader.upload(imagesEncoded))
                         .whenComplete( (result, error) -> {
                             deferredResult.setResult(result);
                             if (null != error) {
                                 logger.error("ERROR: " + error.getMessage());
                             }
                         });
        return deferredResult;
    }
kami
  • 189
  • 1
  • 9