简体   繁体   中英

Java - Using HttpURLConnection to make POST request and send image to server

I'm working on a team software project that involves designing a client for a server-based AI called SeeFood. You can send it a picture, and it will tell you whether or not the picture has food in it. We currently have a python script deployed to the server that accepts Http POST requests and calls the AI with an image that it is given. You can access that at 34.236.92.140.

The challenge I'm facing right now is getting my Java client to be able to send an image to the server, have it analyzed, and get a response back. I've been trying different things, including the Apache HttpComponents library, but I'm constantly getting this response code from the server when I run the code:

400 BAD REQUEST
Server: Apache/2.4.27 (Amazon) PHP/5.6.30 mod_wsgi/3.5 Python/2.7.12
Connection: close
Content-Length: 192
Date: Fri, 17 Nov 2017 16:11:28 GMT
Content-Type: text/html; charset=UTF-8

Judging by research done on HTTP code 400, the server doesn't like how I've formatted the POST request. Does anyone have experience with HTTP servers and sending images via POST? Again, you can try out the server side application at 34.236.92.140. I'll also include the Java client and Python server code.

Java Client (relevant code under the exportImages and readResultsToString methods):

package javaapplication12;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.*;
import static javafx.application.Application.launch;
import javafx.event.*;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.*;

public class UserInterface extends Application {
    private List<File> _images;
    /**
     * @param args the command line arguments
     */
public static void main (String[] args) {
    System.setProperty("java.net.preferIPv4Stack" , "true");
    launch (args);
}

@Override
public void start (Stage primaryStage) {
    final FileChooser fc=new FileChooser ();
    primaryStage.setTitle ("SeeFood AI User Interface");
    Button imageButton=new Button ("Import Images");
    Button exportButton=new Button ("Send Images to SeeFood");
    //When image button is pressed, a FileChooser should load up and add all selected images to a list
    imageButton.setOnAction ((ActionEvent event) -> {
        _images=fc.showOpenMultipleDialog (primaryStage);
        if (_images!=null) {
            int i=0;
            //loop to verify that all selected images are added
            for (File file:_images) {
                System.out.println ("image "+i);
                i++;
            }
        }
    });

    exportButton.setOnAction ((ActionEvent event) -> {
        try {
            exportImages();
        } catch (IOException ex) {
            Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
        }
    });
    final GridPane inputGridPane=new GridPane ();

    GridPane.setConstraints (imageButton,0,0);
    GridPane.setConstraints (exportButton,0,1);
    inputGridPane.setHgap (6);
    inputGridPane.setVgap (6);
    inputGridPane.getChildren ().addAll (imageButton, exportButton);

    final Pane rootGroup=new VBox (12);
    rootGroup.getChildren ().addAll (inputGridPane);
    rootGroup.setPadding (new Insets (12,12,12,12));
    primaryStage.setScene (new Scene (rootGroup));
    primaryStage.show ();
}
/**
 * Sends one or more images to SeeFood via HTTP POST.
 * @throws MalformedURLException
 * @throws IOException 
 */
private void exportImages() throws MalformedURLException, IOException{       
    //InetAddress host=InetAddress.getByName(_ip);
//        System.out.println(InetAddress.getByName(_ip));
    URL url=new URL("http://34.236.92.140");
    HttpURLConnection con=(HttpURLConnection) url.openConnection();
    String output;

    con.setRequestMethod("POST");
    con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
    con.setRequestProperty("Content-Type", "multipart/form-data");

    FileChannel in;
    WritableByteChannel out;

    con.setDoOutput(true);  //this must be set to true in order to work
    con.setDoInput(true);

    for(File file:_images){
        in=new FileInputStream(file).getChannel();
        out=Channels.newChannel(con.getOutputStream());

        in.transferTo(0, file.length(), out);

        StringBuilder builder = new StringBuilder();
        builder.append(con.getResponseCode())
               .append(" ")
               .append(con.getResponseMessage())
               .append("\n");

        Map<String, List<String>> map = con.getHeaderFields();
        for (Map.Entry<String, List<String>> entry : map.entrySet()){
            if (entry.getKey() == null) 
                continue;
            builder.append( entry.getKey())
                   .append(": ");

            List<String> headerValues = entry.getValue();
            Iterator<String> it = headerValues.iterator();
            if (it.hasNext()) {
                builder.append(it.next());

                while (it.hasNext()) {
                    builder.append(", ")
                           .append(it.next());
                }
            }

            builder.append("\n");
        }

        System.out.println(builder);
         //Output the result from SeeFood
        //Later on, this result should be stored for each image
        output=readResultsToString(con);


        if(output!=null){
            System.out.println(output);
        } else {
            System.out.println("There was an error in the connection.");
        }
        in.close();
        out.close();
    }       
    con.disconnect();
}

/**
 * Helper method to exportImages(). Should get response from server
 * and append contents to string.
 * @param con - the active http connection
 * @return response from the server
 */
private String readResultsToString(HttpURLConnection con){
    String result = null;
    StringBuffer sb = new StringBuffer();
    InputStream is = null;

    try {          
        is=new BufferedInputStream(con.getInputStream());
        BufferedReader br=new BufferedReader(new InputStreamReader(is));
        String inputLine="";
        while((inputLine=br.readLine())!=null){
            sb.append(inputLine);
        }
        result=sb.toString();
    } catch (IOException ex) {
        Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
    } finally {
        if(is!=null){
            try {
                is.close();
            } catch (IOException ex) {
                Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    return result;
}
}

Python server:

from flask import Flask, send_from_directory, request
from werkzeug.utils import secure_filename
import argparse
import numpy as np
import tensorflow as tf
from PIL import Image
import sys

app = Flask(__name__)

'''
method for uploading files to the server 
via http POST request
'''
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['file']
        f.save(secure_filename(f.filename))
        print f.filename
        score = ai_call(f.filename)
        #save file in location based on score
        return score

    return '''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form method=post enctype=multipart/form-data>
  <p><input type=file name=file>
     <input type=submit value=Upload>
</form>
'''
'''
method for returning files from the server based on filename
'''
@app.route('/download/<file_name>')
def get_file(file_name):
    return app.send_static_file(file_name)

'''
index page
needs to be motifed to return default images
'''
@app.route('/')
def index():
    find_food
    return 'Hello World'

"""
A script to ask SeeFood if it sees food in the image at 
path specified by the command line argument.
"""
def ai_call(system_arg):
    #parser = argparse.ArgumentParser(description="Ask SeeFood if there is 
food in the image provided.")
#parser.add_argument('image_path', help="The full path to an image file stored on disk.")
#args = parser.parse_args()

# The script assumes the args are perfect, this will crash and burn otherwise.

###### Initialization code - we only need to run this once and keep in memory.
sess = tf.Session()
saver = tf.train.import_meta_graph('saved_model/model_epoch5.ckpt.meta')
saver.restore(sess, tf.train.latest_checkpoint('saved_model/'))
graph = tf.get_default_graph()
x_input = graph.get_tensor_by_name('Input_xn/Placeholder:0')
keep_prob = graph.get_tensor_by_name('Placeholder:0')
class_scores = graph.get_tensor_by_name("fc8/fc8:0")
######

# Work in RGBA space (A=alpha) since png's come in as RGBA, jpeg come in as RGB
# so convert everything to RGBA and then to RGB.
#image_path = args.image_path
image_path = system_arg
image = Image.open(image_path).convert('RGB')
image = image.resize((227, 227), Image.BILINEAR)
img_tensor = [np.asarray(image, dtype=np.float32)]
print 'looking for food in '+ image_path

#Run the image in the model.
scores = sess.run(class_scores, {x_input: img_tensor, keep_prob: 1.})
print scores
# if np.argmax = 0; then the first class_score was higher, e.g., the model sees food.
# if np.argmax = 1; then the second class_score was higher, e.g., the model does not see food.
if np.argmax(scores) == 1:
    print "No food here... :disappointed: "
else:
    print "Oh yes... I see food! :D"
return str(scores)

if __name__ == '__main__':
app.debug = True
app.run()

Any help you can offer is appreciated. Thank you in advance.

I had a similar problem. I fixed it by -

String url = "http://127.0.0.1:8080/";
// 2. create obj for the URL class
        URL obj = new URL(url);
        // 3. open connection on the url
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();
        con.setRequestMethod("POST");
        con.setRequestProperty("Content-Type","image/jpeg");
        con.setDoInput(true);
        con.setDoOutput(true);
        OutputStream out = con.getOutputStream();
        DataOutputStream image = new DataOutputStream(out);

Path path = Paths.get("jpeg.jpg");
byte[] fileContents =  Files.readAllBytes(path);
image.write(fileContents, 0, fileContents.length);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM