【问题标题】:How to stream a JSON object to a HttpURLConnection POST request如何将 JSON 对象流式传输到 HttpURLConnection POST 请求
【发布时间】:2014-02-23 20:57:08
【问题描述】:

我看不出这段代码有什么问题:

JSONObject msg;  //passed in as a parameter to this method

HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
httpCon.setDoOutput(true);
httpCon.setDoInput(true);
httpCon.setUseCaches(false);
httpCon.setRequestProperty( "Content-Type", "application/json" );
httpCon.setRequestProperty("Accept", "application/json");
httpCon.setRequestMethod("POST");
OutputStream os = httpCon.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
msg.write(osw);
osw.flush();
osw.close();    
os.close();     //probably overkill

在服务器上,我根本没有收到任何帖子内容,一个零长度的字符串。

【问题讨论】:

  • 我知道它看起来很奇怪,但是 JSONObject 类有一个 write 方法,您可以将 Writer 对象传递给该方法,并且该类将自身写入流中。这比转换为字符串然后写入字符串要高效得多。在这种情况下,这并没有真正的区别,我们可以将任何东西蒸到 Writer 上,测试是一样的。错误是关于获取连接的。

标签: java post httpurlconnection


【解决方案1】:

试试

...
httpCon.setRequestMethod("POST");
httpCon.connect(); // Note the connect() here
...
OutputStream os = httpCon.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
...    
osw.write(msg.toString());
osw.flush();
osw.close();

发送数据。

检索数据尝试:

BufferedReader br = new BufferedReader(new InputStreamReader( httpCon.getInputStream(),"utf-8"));
String line = null;
while ((line = br.readLine()) != null) {
    sb.append(line + "\n");
}
br.close();
System.out.println(""+sb.toString());

【讨论】:

  • 我不使用“msg.toString()”的原因是我不想制作数据的第二个副本。我一直使用 msg.write() 写入文件写入器,所以我知道这会正确写入流。唯一的其他区别是调用“连接”我会尝试。
  • 是的,“连接”似乎修复了它(这很奇怪,因为服务器收到了请求,所以建立了连接,但显然“连接”实际上发送了正文?在哪里有限制连接必须完成吗?在 headers 之后和 getOutputStream 之前?
  • JavaDoc 说“URLConnection 对象经历了两个阶段:首先创建它们,然后连接它们。创建之后和连接之前,可以指定各种选项(例如,doInput 和 UseCaches)。连接后,尝试设置它们是错误的。依赖于连接的操作,如getContentLength,将在必要时隐式执行连接。”。也许 close() 强制 connect() 但 flush() 太早了?此外,甚至已经触发了 OSW 上的 close()。
【解决方案2】:
 public String sendHTTPData(String urlpath, JSONObject json) {
        HttpURLConnection connection = null;
        try {
            URL url=new URL(urlpath);
            connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/json");
            connection.setRequestProperty("Accept", "application/json");
            OutputStreamWriter streamWriter = new OutputStreamWriter(connection.getOutputStream());
            streamWriter.write(json.toString());
            streamWriter.flush();
            StringBuilder stringBuilder = new StringBuilder();
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK){
                InputStreamReader streamReader = new InputStreamReader(connection.getInputStream());
                BufferedReader bufferedReader = new BufferedReader(streamReader);
                String response = null;
                while ((response = bufferedReader.readLine()) != null) {
                    stringBuilder.append(response + "\n");
                }
                bufferedReader.close();

                Log.d("test", stringBuilder.toString());
                return stringBuilder.toString();
            } else {
                Log.e("test", connection.getResponseMessage());
                return null;
            }
        } catch (Exception exception){
            Log.e("test", exception.toString());
            return null;
        } finally {
            if (connection != null){
                connection.disconnect();
            }
        }
    }`

在 asynctask 的 doitbackground 中调用这个方法

【讨论】:

    【解决方案3】:

    HttpURLConnection 使用起来很麻烦。使用 DavidWebb,一个围绕 HttpURLConnection 的小包装,你可以这样写:

    JSONObject msg;  //passed in as a parameter to this method
    
    Webb webb = Webb.create();
    JSONObject result = webb.post("http://my-url/path/to/res")
        .useCaches(false)
        .body(msg)
        .ensureSuccess()
        .asJsonObject()
        .getBody();
    

    如果您不喜欢它,在提供的链接上有一个替代库列表。

    为什么我们每天都应该编写相同的样板代码?顺便说一句,上面的代码更具可读性且不易出错。 HttpURLConnection 的界面很糟糕。这个必须包起来!

    【讨论】:

    • 这个 .body 是否处理流式 JSON 而不是序列化 JSON 的类似 DOM 的 JsonObject 方式?我的意思是,如果我想按照sites.google.com/site/gson/streaming 使用 GSON 流,这个 Webb 会处理吗?
    • 它看起来很有趣,我想我会尝试一下,因为它很容易进行 GZIP 压缩。但我找不到有关支持流式 JSON 的任何信息
    • 看看issue。谢谢@realavaloro。如果我们能找到解决方案,我会更新答案。
    • 哇,看起来非常漂亮和简单。如何获取 HTTP(s) 响应代码?比如 200、401..?
    • @RageCompex 你可以访问状态码和其他东西like in this example/test-case
    【解决方案4】:

    按照这个例子:

    public static PricesResponse getResponse(EventRequestRaw request) {
    
        // String urlParameters  = "param1=a&param2=b&param3=c";
        String urlParameters = Piping.serialize(request);
    
        HttpURLConnection conn = RestClient.getPOSTConnection(endPoint, urlParameters);
    
        PricesResponse response = null;
    
        try {
            // POST
            OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
            writer.write(urlParameters);
            writer.flush();
    
            // RESPONSE
            BufferedReader reader = new BufferedReader(new InputStreamReader((conn.getInputStream()), StandardCharsets.UTF_8));
            String json = Buffering.getString(reader);
            response = (PricesResponse) Piping.deserialize(json, PricesResponse.class);
    
            writer.close();
            reader.close();
    
        } catch (Exception e) {
            e.printStackTrace();
        }
    
        conn.disconnect();
    
        System.out.println("PricesClient: " + response.toString());
    
        return response;
    }
    
    
    public static HttpURLConnection getPOSTConnection(String endPoint, String urlParameters) {
    
        return RestClient.getConnection(endPoint, "POST", urlParameters);
    
    }
    
    
    public static HttpURLConnection getConnection(String endPoint, String method, String urlParameters) {
    
        System.out.println("ENDPOINT " + endPoint + " METHOD " + method);
        HttpURLConnection conn = null;
    
        try {
            URL url = new URL(endPoint);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod(method);
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Type", "text/plain");
    
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        return conn;
    }
    

    【讨论】:

      【解决方案5】:

      这个不带 json 字符串的 post 数据到服务器

       class PostLogin extends AsyncTask<Void, Void, String> {
              @Override
              protected String doInBackground(Void... params) {
                  String response = null;
      
                  Uri.Builder builder= new Uri.Builder().appendQueryParameter("username","amit").appendQueryParameter("password", "amit");
                  String parm=builder.build().getEncodedQuery();
            try
                 {
      
                     response = postData("your url here/",parm);
                 }catch (Exception e)
                 {
                     e.printStackTrace();
                 }
                  Log.d("test", "response string is:" + response);
                  return response;
              }
          }
      
      
      private String postData(String path, String param)throws IOException {
              StringBuffer response = null;
      
              URL  url = new URL(path);
              HttpURLConnection  connection = (HttpURLConnection) url.openConnection();
              connection.setRequestMethod("POST");
              connection.setDoOutput(true);
      //        connection.setRequestProperty("Content-Type", "application/json");
      //        connection.setRequestProperty("Accept", "application/json");
                  OutputStream out = connection.getOutputStream();
                  out.write(param.getBytes());
                  out.flush();
                  out.close();
                  int responseCode = connection.getResponseCode();
                  if (responseCode == HttpURLConnection.HTTP_OK) {
                      BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                      String line;
                      response = new StringBuffer();
                      while ((line = br.readLine()) != null) {
                          response.append(line);
                      }
                      br.close();
                  }
      
              return response.toString();
          }
      

      【讨论】:

        猜你喜欢
        • 2017-02-22
        • 1970-01-01
        • 2019-08-16
        • 2013-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-23
        • 1970-01-01
        相关资源
        最近更新 更多