使用 java HTTP POST 连接发送图像文件

问题描述 投票:0回答:6

我正在尝试使用 Java HTTP POST 请求将图像发送到网站。

我正在使用此处使用的基本代码将文件从Java客户端上传到HTTP服务器

这是我的修改:

String urlToConnect = "http://localhost:9000/upload";
File fileToUpload = new File("C:\\Users\\joao\\Pictures\\bla.jpg");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.

URLConnection connection = new URL(urlToConnect).openConnection();
connection.setDoOutput(true); // This sets request method to POST.
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
PrintWriter writer = null;
try {
    writer = new PrintWriter(new OutputStreamWriter(connection.getOutputStream()));
    writer.println("--" + boundary);
    writer.println("Content-Disposition: form-data; name=\"picture\"; filename=\"bla.jpg\"");
    writer.println("Content-Type: image/jpeg");
    writer.println();
    BufferedReader reader = null;
    try {
        reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileToUpload)));
        for (String line; (line = reader.readLine()) != null;) {
            writer.println(line);
        }
    } finally {
        if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
    }
    writer.println("--" + boundary + "--");
} finally {
    if (writer != null) writer.close();
}

// Connection is lazily executed whenever you request any status.
int responseCode = ((HttpURLConnection) connection).getResponseCode();
System.out.println(responseCode); // Should be 200

我最终得到了 200 响应代码,但图像有错误,如随机颜色,这让我认为这是字符编码中的错误。我尝试像原始示例一样使用 UTF-8,但这只会创建损坏的图像。

我也 100% 确定这不是服务器端问题,因为我可以使用高级休息客户端/邮递员等休息客户端,并且它们可以毫无问题地发送图像。

你能帮我找出问题所在吗?谢谢你。

java http post upload
6个回答
19
投票
import java.io.File;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;


public class PostFile {
  public static void main(String[] args) throws Exception {
    HttpClient httpclient = new DefaultHttpClient();
    httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);

    HttpPost httppost = new HttpPost("http://localhost:9000/upload");
    File file = new File("C:\\Users\\joao\\Pictures\\bla.jpg");

    MultipartEntity mpEntity = new MultipartEntity();
    ContentBody cbFile = new FileBody(file, "image/jpeg");
    mpEntity.addPart("userfile", cbFile);


    httppost.setEntity(mpEntity);
    System.out.println("executing request " + httppost.getRequestLine());
    HttpResponse response = httpclient.execute(httppost);
    HttpEntity resEntity = response.getEntity();

    System.out.println(response.getStatusLine());
    if (resEntity != null) {
      System.out.println(EntityUtils.toString(resEntity));
    }
    if (resEntity != null) {
      resEntity.consumeContent();
    }

    httpclient.getConnectionManager().shutdown();
  }
}

使用 HttpClient 来计算此代码。使用稳定的库总是比从头开始处理更好,除非需要以自定义方式处理某些内容。


4
投票

今天我遇到了同样的问题,我写了一些nodejs服务器只支持两种路由,上传和下载图像。

客户端应该是一个java类,它通过HTTP POST multipart/form-data标准将图像有效负载发送到服务器。

如果您想知道为什么HTTP POST multipart/form-data,请查看这篇文章中 Ciro Santilli 的答案:What does enctype='multipart/form-data' 是什么意思?

幸运的是,我发现了这个很好的示例代码:

https://www.techcoil.com/blog/how-to-upload-a-file-via-a-http-multipart-request-in-java-without-using-any-external-libraries/

它展示了我们如何在没有任何外部库的情况下手动构建多部分http主体的有效负载,从我的角度来看,唯一的限制是它只能处理带有一个文件的多部分主体。


因为我没有 HTML 页面来嗅探生成的 POST 有效负载,所以我使用 python 来生成它并通过 wireshark 嗅探它。

Python3代码:

import requests
posturl = 'http://<server>:<port>/<path>'
files = {'image' : open('<file>', 'rb')}
r = requests.post(posturl, files = files)

请注意:如果我们使用字典从请求库中定义参数files,它会生成一个多部分/表单数据内容。 http://docs.python-requests.org/en/master/user/advanced/#post-multiple-multipart-encoded-files

Wireshark 将一切显示得非常清楚,最后我用这个来发送 java:

HttpURLConnection conn =
        (HttpURLConnection) new URL("http://<server>:<port>/<path>")).openConnection();

// some arbitrary text for multitext boundary
// only 7-bit US-ASCII digits max length 70
String boundary_string = "some radom/arbitrary text";

// we want to write out
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.addRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary_string);

// now we write out the multipart to the body
OutputStream conn_out = conn.getOutputStream();
BufferedWriter conn_out_writer = new BufferedWriter(new OutputStreamWriter(conn_out));
// write out multitext body based on w3 standard
// https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
conn_out_writer.write("\r\n--" + boundary_string + "\r\n");
conn_out_writer.write("Content-Disposition: form-data; " +
        "name=\"image\"; " +
        "filename=\""+ <File class instance>.getName() +"\"" +
        "\r\n\r\n");
conn_out_writer.flush();

// payload from the file
FileInputStream file_stream = new FileInputStream(<File class instance>);
// write direct to outputstream instance, because we write now bytes and not strings
int read_bytes;
byte[] buffer = new byte[1024];
while((read_bytes = file_stream.read(buffer)) != -1) {
conn_out.write(buffer, 0, read_bytes);
}
conn_out.flush();
// close multipart body
conn_out_writer.write("\r\n--" + boundary_string + "--\r\n");
conn_out_writer.flush();

// close all the streams
conn_out_writer.close();
conn_out.close();
file_stream.close();
// execute and get response code
conn.getResponseCode();

要从 POST 获取响应,只需读取通过 getInputStream() 访问的输入流,代码片段在链接中。


3
投票

Reader/Writer 类旨在处理文本数据,而图像是二进制的。您需要将文件解释为二进制文件:

FileChannel         in  = new FileInputStream(fileToUpload).getChannel();
WritableByteChannel out = Channels.newChannel(connection.getOutputStream());

in.transferTo(0, fileToUpload.size(), out)

当然,你还是需要关闭所有打开的资源。


2
投票

尝试一下:

private DefaultHttpClient mHttpClient;
Context context;
public String error = "";

//Contrutor para que metodos possam ser usados fora de uma activity
public HTTPconector(Context context) {
    this.context = context;
}


public HTTPconector() {
    HttpParams params = new BasicHttpParams();
    params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
    mHttpClient = new DefaultHttpClient(params);
}


public void FileClientPost(String txtUrl, File file){
    try
    {
        error = "";
        HttpPost httppost = new HttpPost(txtUrl);
        MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
        multipartEntity.addPart("Image", new FileBody(file));
        httppost.setEntity(multipartEntity);
        mHttpClient.execute(httppost, new PhotoUploadResponseHandler());
    }
    catch (Exception e)
    {
        Log.e(HTTPconector.class.getName(), e.getLocalizedMessage(), e);
        e.getStackTrace();
        error = e.getMessage();
    }
}

//Verifica se a rede esta disponível
public boolean isNetworkAvailable() {
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = cm.getActiveNetworkInfo();
    // if no network is available networkInfo will be null
    // otherwise check if we are connected
    if (networkInfo != null && networkInfo.isConnected()) {
        return true;
    }
    return false;
}

public String Get(String txtUrl){
    try {
        URL url = new URL(txtUrl);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setReadTimeout(10000);
        con.setConnectTimeout(15000);
        con.setRequestMethod("GET");
        con.setDoInput(true);
        con.connect();

        return readStream(con.getInputStream());

    }  catch (ProtocolException e) {
        e.printStackTrace();
        return "ERRO: "+e.getMessage();
    } catch (IOException e) {
        e.printStackTrace();
        return "ERRO: "+e.getMessage();
    }
}


public String Post(String txtUrl){
    File image;

    try {
        URL url = new URL(txtUrl);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setRequestMethod("POST");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.connect();

        //con.getOutputStream().write( ("name=" + "aa").getBytes());

        return readStream(con.getInputStream());
    } catch (ProtocolException e) {
        e.printStackTrace();
        return "ERRO: "+e.getMessage();
    } catch (IOException e) {
        e.printStackTrace();
        return "ERRO: "+e.getMessage();
    }
}


//Usado para fazer conexão com a internet
public String conectar(String u){
    String resultServer = "";
    try {
        URL url = new URL(u);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        resultServer = readStream(con.getInputStream());
    } catch (Exception e) {
        e.printStackTrace();
        resultServer = "ERRO: "+ e.getMessage();
    }

    Log.i("HTTPMANAGER: ", resultServer);
    return resultServer;
}

//Lê o resultado da conexão
private String readStream(InputStream in) {
    String serverResult = "";
    BufferedReader reader = null;
    try {
        reader = new BufferedReader(new InputStreamReader(in));
        String line = "";
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }

        serverResult = reader.toString();
    }   catch (IOException e) {
        e.printStackTrace();
        serverResult = "ERRO: "+ e.getMessage();
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
                serverResult = "ERRO: "+ e.getMessage();
            }
        }
    }
    return  serverResult;
}

private class PhotoUploadResponseHandler implements ResponseHandler<Object>
{
    @Override
    public Object handleResponse(HttpResponse response)throws ClientProtocolException, IOException {

        HttpEntity r_entity = response.getEntity();
        String responseString = EntityUtils.toString(r_entity);
        Log.d("UPLOAD", responseString);
        return null;
    }
}

0
投票
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
   
   public void fileClientPost(){
        HttpClient httpClient = HttpClientBuilder.create().build();
        BasicHttpContext localContext = new BasicHttpContext();
        
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("...", "...");

        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        HttpEntity entity = (HttpEntity) builder.addPart("file", new FileBody(new File("image.jpg")));
        httpPost.setEntity(entity);

        HttpResponse response = httpClient.execute(httpPost, localContext);
    }

0
投票

以下代码适用于 Kotlin。安卓 11+。

Fragment 中的调用如下所示:

val formData = mapOf(
            "logdata" to "7780456",
            "photo" to encodedBitmap,
}
val url = "https://www.your_server-com/your_php_code.php"
    GlobalScope.launch(Dispatchers.Main) {
        var returnText = httpHelper.sendFormData(url, formData)
        showToast(requireContext(), returnText)
}

HttpHelper 类内部:

suspend fun sendFormData(url: String, formData: Map<String, String>): String {
    return withContext(Dispatchers.IO) {
        var result = ""
        try {
            val connection = URL(url).openConnection() as HttpURLConnection
            connection.connectTimeout = 10000 // 10 seconds
            connection.readTimeout = 20000 // 20 seconds
            connection.requestMethod = "POST"
            connection.doOutput = true
            connection.doInput = true
            connection.useCaches = false;

            val boundary = "*****"
            connection.setRequestProperty("Connection", "Keep-Alive")
            connection.setRequestProperty("Cache-Control", "no-cache");
            connection.setRequestProperty(
                "Content-Type",
                "multipart/form-data;boundary=$boundary"
            )

            val outputStream = connection.outputStream
            val writer = PrintWriter(OutputStreamWriter(outputStream, "UTF-8"), false)
            val os = DataOutputStream(outputStream)

            // Write form data
            for ((key, value) in formData) {
                if (key != "photo") {
                    writer.write("--$boundary\r\n")
                    writer.write("Content-Disposition: form-data; name=\"$key\"\r\n")
                    writer.write("\r\n")
                    writer.write(value)
                    writer.write("\r\n")
                }
            }

            // Write image data
            val imageKey = "photo"
            if (formData.containsKey(imageKey)) {
                writer.write("--$boundary\r\n")
                writer.write("Content-Disposition: form-data; name=\"$imageKey\"; filename=\"photo.jpg\"\r\n")
                writer.write("Content-Type: image/jpeg\r\n")
                writer.write("\r\n")
                writer.flush()

                val imageData = Base64.decode(formData[imageKey], Base64.DEFAULT)
                os.write(imageData)
                os.write("\r\n".toByteArray())
            }

            writer.write("--$boundary--\r\n")
            writer.flush()
            writer.close()

            // Read response
            val responseCode = connection.responseCode
            if (responseCode == HttpURLConnection.HTTP_OK) {
                val inputStream = connection.inputStream
                val reader = BufferedReader(InputStreamReader(inputStream))
                val response = StringBuffer()

                var line: String?
                while (reader.readLine().also { line = it } != null) {
                    response.append(line)
                }

                reader.close()
                connection.disconnect()

                result= response.toString()
            } else {
                // Handle error
                // For example: throw an exception or return an error message
                result = "Error: HTTP $responseCode"
            }
        } catch (e: Exception) {
            // Handle exceptions
            result = "Error: ${e.message}"
        }
        result
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.