python Java使用HttpURLConnection发出POST请求并将图像发送到服务器
我正在从事一个团队软件项目,该项目涉及为名为SeeFood的基于服务器的AI设计一个客户端。你可以给它发一张照片,它会告诉你照片里是否有食物。目前,我们在服务器上部署了一个python脚本,它接受Http POST请求并使用给定的映像调用AI。您可以在34.236.92.140访问该网站
我现在面临的挑战是让我的Java客户机能够向服务器发送一个映像,对其进行分析,并获得响应。我一直在尝试不同的东西,包括Apache HttpComponents库,但在运行代码时,我不断从服务器获得以下响应代码:
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
根据对HTTP代码400的研究判断,服务器不喜欢我格式化POST请求的方式。有没有人有使用HTTP服务器和通过POST发送图像的经验?同样,您可以在34.236.92.140尝试服务器端应用程序。我还将包括Java客户机和Python服务器代码
Java客户端(exportImages和readResultsToString方法下的相关代码):
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服务器:
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()
非常感谢您提供的任何帮助。先谢谢你
# 1 楼答案
我也有类似的问题。我通过以下方式修正了它: