2

Я пытаюсь отправить изображение на сервер с помощью HttpUrlConnection, потому что он рекомендуется Google. Я решил преобразовать изображение в строку Base64 и отправить его на сервер, где я его расшифровал в .jpg файл. Но этот метод возможен только с миниатюрами небольшого размера, и я не могу отправить полноразмерные изображения.Как отправить изображение с Android-клиента на сервер Node.js через HttpUrlConnection?

Вот андроид код клиента:

public static void postData(Bitmap imageToSend) { 



     try 

     { 
      URL url = new URL("http://"); 
      HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
      conn.setRequestMethod("POST"); 

      conn.setDoInput(true); 
      conn.setDoOutput(true); 

      conn.setRequestProperty("Connection", "Keep-Alive"); 
      conn.setRequestProperty("Cache-Control", "no-cache"); 

      conn.setReadTimeout(35000); 
      conn.setConnectTimeout(35000); 


      ByteArrayOutputStream bos = new ByteArrayOutputStream(); 

      // writes a compress version of Bitmap to a specified outputstream 
      imageToSend.compress(Bitmap.CompressFormat.JPEG, 100, bos); 

      byte[] byteArray = bos.toByteArray(); 
      String imageEncoded = Base64.encodeToString(byteArray, Base64.DEFAULT); 

      List<NameValuePair> params = new ArrayList<NameValuePair>(); 
      params.add(new BasicNameValuePair("image", imageEncoded)); 


      OutputStream os = conn.getOutputStream(); 
      BufferedWriter writer = new BufferedWriter(
        new OutputStreamWriter(os, "UTF-8")); 

      // getQuery is function for creating a URL encoded string 
      writer.write(getQuery(params)); 

      System.out.println("Response Code: " + conn.getResponseCode()); 

      InputStream in = new BufferedInputStream(conn.getInputStream()); 
      Log.d("sdfs", "sfsd"); 
      BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(in)); 
      String line = ""; 
      StringBuilder stringBuilder = new StringBuilder(); 
      while ((line = responseStreamReader.readLine()) != null) 
       stringBuilder.append(line).append("\n"); 
      responseStreamReader.close(); 

      String response = stringBuilder.toString(); 
      System.out.println(response); 

      bos.flush(); 
      bos.close(); 
      in.close(); 
      conn.disconnect(); 

     } 

     catch(MalformedURLException e) { 
      e.printStackTrace(); 
     } 

     catch(IOException e) { 
      e.printStackTrace(); 
     } 


} 

Node.js код сервера:

function base64_decode(base64str,file) { 
 
    var bitmap = new Buffer(base64str,'base64'); 
 
    //writing into an image file 
 
    fs.writeFile(file, bitmap); 
 
    //write a text file 
 
    console.log('File created from base64 encoded string'); 
 
} 
 

 
app.post("/", function (req,res,next) { 
 
     //requesting the value of the image key which is urlencoded base 64 string 
 
     var image = req.body.image; 
 
     console.log(req.body.image); 
 
     base64_decode(image,'newImage.jpg'); 
 

 
     res.writeHead(200, {'Content-Type':'text/plain'}); 
 
     res.write('the image is saved'); 
 
     res.end(); 
 
     if (req.url != "/") 
 
      next(); 
 

Я не могу использовать тот же метод для полноразмерных изображений, из-за ограничений размера BufferedWriter - строка с кодировкой base64 слишком длинная для нее.

Другой метод использует HttpPost и MultipartEntity, но оба они устарели в API22, и я не знал, как обрабатывать запрос на стороне сервера. В других примерах использовались некоторые обертки, такие как два дефиса, границы, crlf, но я не мог найти почему.

мне нужен пример с HttpURLConnection

Любая помощь приветствуется, потому что я новичок в Android и node.js

+0

Если вы хотите избежать беспорядка с помощью 'HttpURLConnection', вы можете взглянуть на [DavidWebb] (http://hgoebl.github.io/DavidWebb/). И если вы используете Express, существует тестовый api-сервер с [некоторым примером кода] (https://github.com/hgoebl/DavidWebb/blob/master/src/test/api-test-server/routes /upload.js#L41-L86), показывающий, как можно выполнить загрузку. Обычно я бы не рекомендовал использовать Base64, вы можете загружать двоичные файлы во всех случаях. Вы открыты для этой библиотеки и Express? – hgoebl

+0

Я использую Express в любом случае. И спасибо за библиотеки, я подумаю об использовании, если не могу понять проблемы HttpUrlConnection. Тем не менее, я вижу в документации, что он не поддерживает многостраничную загрузку – Azik

ответ

2

Я рекомендую загружать двоичные данные. Вы можете разместить метаданные изображения (например, имя, тип, идентификатор пользователя, ...) в качестве параметров URL или пользовательских http-заголовков (X -...).

код Android-клиент (не тестировался!):

public static void postData(Bitmap imageToSend) { 
     try 
     { 
      URL url = new URL("http://myserver/myapp/upload-image"); 
      HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
      conn.setRequestMethod("POST"); 

      conn.setDoInput(true); 
      conn.setDoOutput(true); 

      conn.setRequestProperty("Connection", "Keep-Alive"); 
      conn.setRequestProperty("Cache-Control", "no-cache"); 

      conn.setReadTimeout(35000); 
      conn.setConnectTimeout(35000); 

      // directly let .compress write binary image data 
      // to the output-stream 
      OutputStream os = conn.getOutputStream(); 
      imageToSend.compress(Bitmap.CompressFormat.JPEG, 100, os); 
      os.flush(); 
      os.close(); 

      System.out.println("Response Code: " + conn.getResponseCode()); 

      InputStream in = new BufferedInputStream(conn.getInputStream()); 
      Log.d("sdfs", "sfsd"); 
      BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(in)); 
      String line = ""; 
      StringBuilder stringBuilder = new StringBuilder(); 
      while ((line = responseStreamReader.readLine()) != null) 
       stringBuilder.append(line).append("\n"); 
      responseStreamReader.close(); 

      String response = stringBuilder.toString(); 
      System.out.println(response); 

      conn.disconnect(); 
     } 
     catch(MalformedURLException e) { 
      e.printStackTrace(); 
     } 
     catch(IOException e) { 
      e.printStackTrace(); 
     } 
} 

Node.js, Экспресс-код:

function rawBody(req, res, next) { 
    var chunks = []; 

    req.on('data', function(chunk) { 
     chunks.push(chunk); 
    }); 

    req.on('end', function() { 
     var buffer = Buffer.concat(chunks); 

     req.bodyLength = buffer.length; 
     req.rawBody = buffer; 
     next(); 
    }); 

    req.on('error', function (err) { 
     console.log(err); 
     res.status(500); 
    }); 
} 

app.post('/upload-image', rawBody, function (req, res) { 

    if (req.rawBody && req.bodyLength > 0) { 

     // TODO save image (req.rawBody) somewhere 

     // send some content as JSON 
     res.send(200, {status: 'OK'}); 
    } else { 
     res.send(500); 
    } 

}); 

Я попытаюсь объяснить Node.js часть: Функция rawBody действует как промежуточное ПО Express. Когда выполняется запрос POST, эта функция вызывается с объектом запроса. Он регистрирует слушателей для data, end и error событий. События data добавляют все входящие фрагменты данных в буфер. Когда end срабатывает, в объекте запроса создается свойство rawBody и содержит двоичные данные (ваше изображение blob). rawBody() затем передает управление следующему обработчику, который теперь может сохранять blob в вашу базу данных или файловую систему.

При работе с действительно большими каплями данных этот вид обработки не самый лучший способ. Было бы лучше передать данные в файл или в базу данных для сохранения памяти.

+0

Вот и все! Большое спасибо!!! Ты спас мне много времени и сил! Я не совсем понял часть node.js, хотя, я собираюсь ее исследовать, или если вы можете объяснить это короче, я был бы очень благодарен! – Azik

1

На данный момент у меня недостаточно очков, поэтому я должен написать целый ответ вместо комментария.

Я хочу добавить несколько слов к ответу hgoebl, что здорово и спасло меня много времени! Благодаря!

Перед тем, как смыть поток, вы должны добавить эти строки, так как без них я не смог его заставить работать.

urlConnection.setRequestProperty("Content-Type", "multipart/form-data"); 
urlConnection.setFixedLengthStreamingMode(1024); 

Если вы хотите читать прямо с вашего USB/SD хранения не должны декодировать ваш Bitmap и кодировать его в сжатом формате. просто сделайте как

// ... set request header 

FileInputStream fis = new FileInputStream(filePath); 

OutputStream os = new BufferedOutputStream(urlConnection.getOutputStream()); 
OutputStreamWriter out = new OutputStreamWriter(os); 

byte[] buffer = new byte[1024]; 
int read; 
while ((read = fis.read(buffer)) != -1) { 
    os.write(buffer, 0, read); 
} 

... // flush and close 

с этим вы должны иметь возможность загружать любые двоичные данные.

Смежные вопросы