1

我一直在尝试从我公司的 json 网络服务中获取 json 响应。这是代码:

public final static String GOINOUT_HOST_NAME = "http://ec2-54-254-123-244.ap-southeast-1.compute.amazonaws.com";
public final static String GOINOUT_API_VERSION = "/api/v1";

public final static String GOINOUT_FACEBOOK_AUTHENTICATE = GOINOUT_HOST_NAME + GOINOUT_API_VERSION + "/facebook_authenticate";

public static JSONObject loginGoinoutWithFacebook(String accessToken) {
    JSONObject goinoutUserJsonObject = null;
    try {
        Hashtable params = new Hashtable();
        params.put("access_token", accessToken);
        String paramsString = StringUtil.toURLParameters(params);

        Hashtable properties = new Hashtable();
        String response = HttpUtils.sendGoinoutJsonRequest(GOINOUT_FACEBOOK_AUTHENTICATE + "?" + paramsString, paramsString, HttpUtils.TIMEOUT, properties, HttpConnection.POST);
        Dialog.alert("res: " + response);
        JSONObject goinoutJsonObject = new JSONObject(response);
        goinoutUserJsonObject = new JSONObject(goinoutJsonObject.getString("user"));
    } catch (IOException e) {
        Dialog.alert("e1: " + e.getMessage());
        e.printStackTrace();
    } catch (JSONException e1) {
        Dialog.alert("e2: " + e1.getMessage());
        e1.printStackTrace();
    }
    return goinoutUserJsonObject;
}

以下代码块是 goinout json 请求:

public static String sendGoinoutJsonRequest(String url,String data,long timeout, Hashtable properties, String method) throws IOException {

    HttpConnectionFactory factory = new HttpConnectionFactory(Util.getTransportPriority());
    while(true) {

        HttpConnectionIOSession httpConnectionIOSession = null;
        try {

            HttpConnection httpConnection = factory.getHttpConnection(url);
            if(httpConnection == null) throw new IOException();
            try {

                httpConnection.setRequestMethod(method);
                httpConnection.setRequestProperty("If-Modified-Since","29 Oct 1999 19:43:31 GMT");
                httpConnection.setRequestProperty("User-Agent","Profile/MIDP-2.0 Configuration/CLDC-1.0");
                httpConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
                httpConnection.setRequestProperty("Accept","application/json");                    
                httpConnection.setRequestProperty("Content-Length",data.getBytes().length + "");
                httpConnection.setRequestProperty("Content-Language","en-US");
                httpConnection.setRequestProperty("x-rim-transcode-content","none");
                Enumeration keys = properties.keys();
                while(keys.hasMoreElements()) {
                    String key = (String) keys.nextElement();
                    String value = (String) properties.get(key);
                    httpConnection.setRequestProperty(key, value);
                }
                OutputStream outputStream = httpConnection.openOutputStream();
                InputStream inputStream = null;
                if(timeout != -1) {

                    httpConnectionIOSession = new HttpConnectionIOSession(httpConnection,inputStream,outputStream,timeout);

                }
                outputStream.write(data.getBytes());
                outputStream.close();
                int responseCode = httpConnection.getResponseCode();
                if(responseCode != HttpConnection.HTTP_OK) {

                    if(responseCode == HttpConnection.HTTP_BAD_REQUEST) {

                        continue;

                    }
                    if(timeout != -1 && HttpUtils.TIMEOUT + 2000 <= TIMEOUT_MIN) {

                        HttpUtils.TIMEOUT += 2000;

                    }
                    throw new IOException("HTTP " + responseCode + " error code.");

                }
                inputStream = httpConnection.openInputStream();
                final ByteBuffer byteBuffer = new ByteBuffer(inputStream);
                final String response = byteBuffer.getString();
                close(httpConnection,inputStream,outputStream);

                if(timeout != -1 && HttpUtils.TIMEOUT - 1000 >= TIMEOUT_MIN) {

                    HttpUtils.TIMEOUT -= 1000;

                }
                if(httpConnectionIOSession != null) httpConnectionIOSession.interrupt();
                return response;

            } catch(IOException ioException) {

                if(timeout != -1 && HttpUtils.TIMEOUT + 2000 <= TIMEOUT_MIN) {

                    HttpUtils.TIMEOUT += 2000;

                }
                throw ioException;


            }

        } catch(IOException ioException) {

            if(timeout != -1 && HttpUtils.TIMEOUT + 2000 <= TIMEOUT_MIN) {

                HttpUtils.TIMEOUT += 2000;

            }
            throw ioException;

        } finally {
            if(httpConnectionIOSession != null) httpConnectionIOSession.interrupt();
        }

    }

}

查看我设置的属性。如果我使用以下属性:

httpConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
httpConnection.setRequestProperty("Accept","application/json");

发生的事情是我可以从我的 BB 模拟器和使用 wifi 连接的真实设备中检索 JSON 数据。但是,当我使用移动服务提供商使用 REAL DEVICE 时,我总是会得到 IOException: stream closed。

如果我使用以下代码:

httpConnection.setRequestProperty("Content-Type","application/json");
httpConnection.setRequestProperty("Accept","application/json");   

我总是在模拟器中收到 HTTP 错误代码 500。如果我在使用移动服务提供商的真实设备中使用此属性,代码将继续运行,因为那里有 while(true)。我想知道你们是否可以帮助我。

事实上,这段代码被证明可以从 Facebook API 和 Tumblr API 获取 json 数据。我总是使用这个代码并且没有问题。我想知道这可能是服务器端有问题,还是我应该添加另一个属性???太感谢了。

对 HttpConnectionFactory 的 Nate 请求:

package com.hammyliem.abateify.ui.network;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Vector;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;

import net.rim.device.api.io.http.HttpHeaders;
import net.rim.device.api.io.http.HttpProtocolConstants;
import net.rim.device.api.servicebook.ServiceBook;
import net.rim.device.api.servicebook.ServiceRecord;
import net.rim.device.api.system.Branding;
import net.rim.device.api.system.CoverageInfo;
import net.rim.device.api.system.DeviceInfo;
import net.rim.device.api.system.WLANInfo;

public class HttpConnectionFactory {

  public static final int TRANSPORT_WIFI = 1;
  public static final int TRANSPORT_BES = 2;
  public static final int TRANSPORT_BIS = 4;
  public static final int TRANSPORT_DIRECT_TCP = 8;
  public static final int TRANSPORT_WAP2 = 16;
  public static final int TRANSPORT_SIM = 32;

  public static final int TRANSPORTS_ANY = TRANSPORT_WIFI | TRANSPORT_BES | TRANSPORT_BIS | TRANSPORT_DIRECT_TCP | TRANSPORT_WAP2 | TRANSPORT_SIM;
  public static final int TRANSPORTS_AVOID_CARRIER = TRANSPORT_WIFI | TRANSPORT_BES | TRANSPORT_BIS | TRANSPORT_SIM;
  public static final int TRANSPORTS_CARRIER_ONLY = TRANSPORT_DIRECT_TCP | TRANSPORT_WAP2 | TRANSPORT_SIM;

  public static final int DEFAULT_TRANSPORT_ORDER[] = { TRANSPORT_WIFI, TRANSPORT_SIM, TRANSPORT_BIS, TRANSPORT_BES, TRANSPORT_WAP2, TRANSPORT_DIRECT_TCP };

  private static final int TRANSPORT_COUNT = DEFAULT_TRANSPORT_ORDER.length;

  // private static ServiceRecord srMDS[], srBIS[], srWAP2[], srWiFi[];
  private static ServiceRecord srWAP2[];
  private static boolean serviceRecordsLoaded = false;

  private int transports[];
  private int lastTransport = -1;

  public HttpConnectionFactory() {
    this(0);
  }

  public HttpConnectionFactory(int allowedTransports) {
    this(transportMaskToArray(allowedTransports));
  }

  public HttpConnectionFactory(int transportPriority[]) {
    if (!serviceRecordsLoaded) {
      loadServiceBooks(false);
    }
    transports = transportPriority;
  }

  public static String getUserAgent() {
    StringBuffer sb = new StringBuffer();
    sb.append("BlackBerry");
    sb.append(DeviceInfo.getDeviceName());
    sb.append("/");
    sb.append(DeviceInfo.getSoftwareVersion());
    sb.append(" Profile/");
    sb.append(System.getProperty("microedition.profiles"));
    sb.append(" Configuration/");
    sb.append(System.getProperty("microedition.configuration"));
    sb.append(" VendorID/");
    sb.append(Branding.getVendorId());

    return sb.toString();
  }

  public static String getProfile() {
    StringBuffer sb = new StringBuffer();
    sb.append("http://www.blackberry.net/go/mobile/profiles/uaprof/");
    sb.append(DeviceInfo.getDeviceName());
    sb.append("/");
    sb.append(DeviceInfo.getSoftwareVersion().substring(0, 3)); //RDF file format is 4.5.0.rdf (does not include build version)
    sb.append(".rdf");

    return sb.toString();
  }

  public HttpConnection getHttpConnection(String pURL) {
    return getHttpConnection(pURL, null, null);
  }

  public HttpConnection getHttpConnection(String pURL, HttpHeaders headers) {
    return getHttpConnection(pURL, headers, null);
  }

  public HttpConnection getHttpConnection(String pURL, byte[] data) {
    return getHttpConnection(pURL, null, data);
  }

  public HttpConnection getHttpConnection(String pURL, HttpHeaders headers, byte[] data) {

    int curIndex = 0;
    HttpConnection con = null;

    while ((con = tryHttpConnection(pURL, curIndex, headers, data)) == null) {
      try {
        curIndex = nextTransport(curIndex);
      } catch (HttpConnectionFactoryException e) {
        e.printStackTrace();
        break;
      } finally {
      }
    }

    if (con != null) {
      setLastTransport(transports[curIndex]);
    }

    return con;
  }

  private int nextTransport(int curIndex) throws HttpConnectionFactoryException {
    if ((curIndex >= 0) && (curIndex < transports.length - 1)) {
      return curIndex + 1;
    } else {
      throw new HttpConnectionFactoryException("No more transport available.");
    }
  }

  private HttpConnection tryHttpConnection(String pURL, int tIndex, HttpHeaders headers, byte[] data) {

    HttpConnection con = null;
    OutputStream os = null;

    switch (transports[tIndex]) {
    case TRANSPORT_SIM:
      try {
        con = getSimConnection(pURL, false);
      } catch (IOException e) {
      } finally {
        break;
      }
    case TRANSPORT_WIFI:
      try {
        con = getWifiConnection(pURL);
      } catch (IOException e) {
      } finally {
        break;
      }
    case TRANSPORT_BES:
      try {
        con = getBesConnection(pURL);
      } catch (IOException e) {
      } finally {
        break;
      }
    case TRANSPORT_BIS:
      try {
        con = getBisConnection(pURL);
      } catch (IOException e) {
      } finally {
        break;
      }
    case TRANSPORT_DIRECT_TCP:
      try {
        con = getTcpConnection(pURL);
      } catch (IOException e) {
      } finally {
        break;
      }
    case TRANSPORT_WAP2:
      try {
        con = getWap2Connection(pURL);
      } catch (IOException e) {
      } finally {
        break;
      }
    }

    if (con != null) {
      try {
        //add headers to connection
        if (headers != null) {
          int size = headers.size();

          for (int i = 0; i < size;) {
            String header = headers.getPropertyKey(i);
            String value = headers.getPropertyValue(i++);

            if (value != null) {
              con.setRequestProperty(header, value);

            }
          }
        }
        // post data
        if (data != null) {
          con.setRequestMethod(HttpConnection.POST);
          con.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_TYPE, HttpProtocolConstants.CONTENT_TYPE_APPLICATION_X_WWW_FORM_URLENCODED);
          con.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH, String.valueOf(data.length));

          os = con.openOutputStream();
          os.write(data);
        } else {
          con.setRequestMethod(HttpConnection.GET);
        }

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

    return con;
  }

  public int getLastTransport() {
    return lastTransport;
  }

  public String getLastTransportName() {
    return getTransportName(getLastTransport());
  }

  private void setLastTransport(int pLastTransport) {
    lastTransport = pLastTransport;
  }

  private HttpConnection getSimConnection(String pURL, boolean mdsSimulatorRunning) throws IOException {
    if (DeviceInfo.isSimulator()) {
      if (mdsSimulatorRunning) {
        return getConnection(pURL, ";deviceside=false", null);
      } else {
        return getConnection(pURL, ";deviceside=true", null);
      }
    }
    return null;
  }

  private HttpConnection getBisConnection(String pURL) throws IOException {
    if (CoverageInfo.isCoverageSufficient(4 /* CoverageInfo.COVERAGE_BIS_B */)) {
      return getConnection(pURL, ";deviceside=false;ConnectionType=mds-public", null);
    }
    return null;
  }

  private HttpConnection getBesConnection(String pURL) throws IOException {
    if (CoverageInfo.isCoverageSufficient(2 /* CoverageInfo.COVERAGE_MDS */)) {
      return getConnection(pURL, ";deviceside=false", null);
    }
    return null;
  }

  private HttpConnection getWifiConnection(String pURL) throws IOException {
    if (WLANInfo.getWLANState() == WLANInfo.WLAN_STATE_CONNECTED) {
      return getConnection(pURL, ";interface=wifi", null);
    }
    return null;
  }

  private HttpConnection getWap2Connection(String pURL) throws IOException {
    if (CoverageInfo.isCoverageSufficient(1 /* CoverageInfo.COVERAGE_DIRECT */) && (srWAP2 != null) && (srWAP2.length != 0)) {
      return getConnection(pURL, ";deviceside=true;ConnectionUID=", srWAP2[0].getUid());
    }
    return null;
  }

  private HttpConnection getTcpConnection(String pURL) throws IOException {
    if (CoverageInfo.isCoverageSufficient(1 /* CoverageInfo.COVERAGE_DIRECT */)) {
      return getConnection(pURL, ";deviceside=true", null);
    }
    return null;
  }

  private HttpConnection getConnection(String pURL, String transportExtras1, String transportExtras2) throws IOException {
    StringBuffer fullUrl = new StringBuffer();
    fullUrl.append(pURL);
    if (transportExtras1 != null) {
      fullUrl.append(transportExtras1);
    }
    if (transportExtras2 != null) {
      fullUrl.append(transportExtras2);
    }
    return (HttpConnection) Connector.open(fullUrl.toString());
  }

  public static void reloadServiceBooks() {
    loadServiceBooks(true);
  }

  private static synchronized void loadServiceBooks(boolean reload) {
    if (serviceRecordsLoaded && !reload) {
      return;
    }
    ServiceBook sb = ServiceBook.getSB();
    ServiceRecord[] records = sb.getRecords();
    Vector mdsVec = new Vector();
    Vector bisVec = new Vector();
    Vector wap2Vec = new Vector();
    Vector wifiVec = new Vector();

    if (!serviceRecordsLoaded) {
      for (int i = 0; i < records.length; i++) {
        ServiceRecord myRecord = records[i];
        String cid, uid;

        if (myRecord.isValid() && !myRecord.isDisabled()) {
          cid = myRecord.getCid().toLowerCase();
          uid = myRecord.getUid().toLowerCase();
          if ((cid.indexOf("wptcp") != -1) && (uid.indexOf("wap2") != -1) && (uid.indexOf("wifi") == -1) && (uid.indexOf("mms") == -1)) {
            wap2Vec.addElement(myRecord);
          }
        }
      }

      srWAP2 = new ServiceRecord[wap2Vec.size()];
      wap2Vec.copyInto(srWAP2);
      wap2Vec.removeAllElements();
      wap2Vec = null;

      serviceRecordsLoaded = true;
    }
  }

  public static int[] transportMaskToArray(int mask) {
    if (mask == 0) {
      mask = TRANSPORTS_ANY;
    }
    int numTransports = 0;
    for (int i = 0; i < TRANSPORT_COUNT; i++) {
      if ((DEFAULT_TRANSPORT_ORDER[i] & mask) != 0) {
        numTransports++;
      }
    }
    int transports[] = new int[numTransports];
    int index = 0;
    for (int i = 0; i < TRANSPORT_COUNT; i++) {
      if ((DEFAULT_TRANSPORT_ORDER[i] & mask) != 0) {
        transports[index++] = DEFAULT_TRANSPORT_ORDER[i];
      }
    }
    return transports;
  }

  private static String getTransportName(int transport) {
    String tName;
    switch (transport) {
    case TRANSPORT_WIFI:
      tName = "WIFI";
      break;
    case TRANSPORT_BES:
      tName = "BES";
      break;
    case TRANSPORT_BIS:
      tName = "BIS";
      break;
    case TRANSPORT_DIRECT_TCP:
      tName = "TCP";
      break;
    case TRANSPORT_WAP2:
      tName = "WAP2";
      break;
    case TRANSPORT_SIM:
      tName = "SIM";
      break;
    default:
      tName = "UNKNOWN";
      break;
    }
    return tName;
  }

}
4

2 回答 2

0

我怀疑这里有两个不同的问题,除了你在事件线程上运行代码的可能性,正如 Nate 指出的那样。

我不确定您是否在事件线程上运行,因为如果您是,您的应用程序将因 Application Not Responding 异常而终止。但正如 Nate 指出的那样,如果您尝试从事件线程中执行一个对话框,您将得到一个异常。所以无论哪种方式,我都希望有一个例外......

总结报告的问题,您似乎得到以下情况之一:a)在设备上使用无线数据服务(而不是 WiFi)运行时连接上出现 IOException b)使用 a 发送数据时出现 HTTP 代码 500特定的标题。这意味着服务器已返回您的请求,告诉您它尚未理解它。所以你发送的东西不正确。

首先,我建议您调查 IOException - 基本上打印出您获得的异常的详细信息(toString() 会这样做)。这将为您提供有关该问题的更多详细信息。有很多选择,我猜这将是一个超时,但在我尝试提出解决方案之前想知道。

我可以参考您之前的主题吗:blackberry-get-error-code-411 请再次阅读我的回复。

其中有两点对所有通信都至关重要,而不仅仅是 411 错误:

  1. 用于传输数据的编码
  2. 使用的连接方法。

编码可能是 500 返回码的关键。当您告诉服务器您正在发送 JSON 数据时,它可能期望数据将采用 UTF-8 编码。但是,您发送的数据似乎不是。如果您只使用标准的 Latin-1 字符,那么这将不是问题。如果您的 JSON 数据包含未包含在该字符集中的字符,则数据将无法正确编码,这可能是您的服务器不理解它的原因。

因此,为了安全起见,在发送 JSON 数据时,我建议您对其进行 UTF-8 编码(请记住,生成的字节数不一定与字符串中的字符数相同)。

进一步关于 500 错误代码(实际上是任何错误代码),我建议您在收到的响应中转储标题。他们可能会识别出实际返回请求的服务器。它可能不是您的服务器 - 当通过移动网络进行处理时,因为涉及的其他网关可以拒绝请求。

总之,要调查此问题(或任何其他网络问题),我建议您:

  1. 从您获得的任何异常中打印出详细信息
  2. 确保您知道失败的请求使用什么连接方法
  3. 如果您没有得到好的返回码,请转储标题,以便找出哪个服务器实际为您提供了返回码
  4. 确保您正确编码(字符编码为字节)您正在发送的数据(如果您将这些数据转换回字符,则正确解码您收到的字节)。

最后一件事。由于服务器给你一个 500 - 我建议你在发送之前记录帖子数据,如果失败,你可以检查它的格式是否正确。

于 2013-11-03T01:36:09.093 回答
0

首先,我有点不清楚为什么这个问题被标记为android。也许为时已晚,我错过了一些东西。无论如何,我作为一个黑莓问题来回答这个问题。

首先,如果您使用普通 URL 编码为您的请求编码一组参数,并在响应中期望 JSON ,那么您的原始代码:

httpConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
httpConnection.setRequestProperty("Accept","application/json");                    

是正确的。如果您的请求内容是 URL 编码的参数,请不要设置Content-Type为。application/json

其次,我不是 100% 确定,但我相信您正在 UI 线程上执行此网络请求。尽管我看不到调用 的代码,但loginGoinoutWithFacebook()我相信您是在 UI 线程上执行的,因为该方法包含对 的调用Dialog.alert(),这是一个 UI 方法。

不要在 UI 线程上进行网络调用!

可能发生的事情(假设您将内容类型设置为application/x-www-form-urlencoded)是通过 Wi-Fi,网络请求完成得非常快,并且 UI 不会被阻塞太久。它似乎工作。

但是,当您使用移动运营商网络时,一切都会变慢。您阻塞 UI 线程的时间过长,这会导致问题。我不记得在 UI 线程上进行网络调用的确切症状是什么(因为我从不这样做),但我敢打赌这是你的问题。

使用背景Thread/Runnable执行您的网络调用:

Thread worker = new Thread(new Runnable() {
   // this method is run on a background thread:
   public void run() {
      final JSONObject response = loginGoinoutWithFacebook(token);

      // to update the UI with the response, we must use the UI thread:
      UiApplication.getUiApplication().invokeLater(new Runnable() {
          public void run() {
              // this just shows an alert, but you can insert your
              //  own code to update the UI properly with the response
              //  contents
              Dialog.alert(response.toString());
          }
      });
   }
});

worker.start();
于 2013-11-02T08:20:04.487 回答