如何在使用Scribe for OAuth请求时解决java.io.EOFException?

时间:2013-06-27 10:53:23

标签: android scribe

如果这是重复的话,我道歉(请链接?)

我遇到这样的运行时错误:

E/AndroidRuntime(26112): FATAL EXCEPTION: AsyncTask #3

E/AndroidRuntime(26112): java.lang.RuntimeException: An error occured while executing doInBackground()

E/AndroidRuntime(26112):    
at android.os.AsyncTask$3.done(AsyncTask.java:299)

E/AndroidRuntime(26112):    
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)

E/AndroidRuntime(26112):    
at java.util.concurrent.FutureTask.setException(FutureTask.java:219)

E/AndroidRuntime(26112):    
at java.util.concurrent.FutureTask.run(FutureTask.java:239)

E/AndroidRuntime(26112):    
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)

E/AndroidRuntime(26112):    
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)

E/AndroidRuntime(26112):    
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)

E/AndroidRuntime(26112):    
at java.lang.Thread.run(Thread.java:856)

E/AndroidRuntime(26112): 
Caused by: org.scribe.exceptions.OAuthException: Problems while creating connection.

E/AndroidRuntime(26112):    
at org.scribe.model.Request.send(Request.java:70)

E/AndroidRuntime(26112):    
at org.scribe.model.OAuthRequest.send(OAuthRequest.java:12)

E/AndroidRuntime(26112):    
at com.notbyimgur.imguraffe.ImageGridActivity$getAccountData.doInBackground(ImageGridActivity.java:1091)

E/AndroidRuntime(26112):    
at com.notbyimgur.imguraffe.ImageGridActivity$getAccountData.doInBackground(ImageGridActivity.java:1)

E/AndroidRuntime(26112):    
at android.os.AsyncTask$2.call(AsyncTask.java:287)

E/AndroidRuntime(26112):    
at java.util.concurrent.FutureTask.run(FutureTask.java:234)

E/AndroidRuntime(26112):    ... 4 more

E/AndroidRuntime(26112): Caused by: java.io.EOFException

E/AndroidRuntime(26112):    at libcore.io.Streams.readAsciiLine(Streams.java:203)

E/AndroidRuntime(26112):    at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:573)

E/AndroidRuntime(26112):    at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:821)

E/AndroidRuntime(26112):    
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283)

E/AndroidRuntime(26112):    
at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:495)

E/AndroidRuntime(26112):    
at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)

E/AndroidRuntime(26112):    at org.scribe.model.Response.<init>(Response.java:28)

E/AndroidRuntime(26112):    at org.scribe.model.Request.doSend(Request.java:110)

E/AndroidRuntime(26112):    at org.scribe.model.Request.send(Request.java:62)

E/AndroidRuntime(26112):    ... 9 more

代码:

仅发布了有问题的部分。 在同一活动中有多个OAuth请求(均在单独的asynctask类中),这些请求可能同时执行,如果这是重要的话。

public class getAccountData extends AsyncTask<Void, Void, dataModels.Account>
    {
        private String url = "";
        private String accessToken = "";    
        private Client_IDs CLID= new Client_IDs();
        public getAccountData(String urlin, AuthenticationToken autht)
        { 
            url = urlin;
            accessToken = autht.accessToken;
        }

        @Override
        protected dataModels.Account doInBackground(Void... params) {

            OAuthService service = new ServiceBuilder()
                            .provider(ImgUr3Api.class)
                            .apiKey(CLID.CLIENT_ID)
                            .apiSecret(CLID.CLIENT_SECRET)
                            .debug()
                            .build();
            OAuthRequest request = new OAuthRequest(Verb.GET, url);
            request.setConnectionKeepAlive(true);
            service.signRequest(new Token(accessToken, null), request);
            Response response = request.send();

            if(response.getBody() != null)
            {   String body = response.getBody();
                dataModels.Account account = new dataModels.Account();
                JSONObject rawData;
                try {
                    rawData = new JSONObject(body);
                    if(rawData.getBoolean("success"))
                    {
                        JSONObject data = rawData.getJSONObject("data");
                        account.id = data.getInt("id");
                        account.bio = data.getString("bio");
                        account.url = data.getString("url");
                        account.reputation = (int)data.getDouble("reputation");
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                return account;
            }
            return null;
        }
        @Override
        protected void onPostExecute(dataModels.Account account)
        {
            if(account !=null)
            {               
                userAcc.id = account.id;
                userAcc.bio = account.bio;
                userAcc.reputation = account.reputation;
                userAcc.url = account.url;
                if(!isCancelled())
                finalizeSlider(true);
            }
        }
    }

我尝试过切换request.setConnectionKeepAlive(true/false)而没有任何积极的结果。除此之外,我无法尝试其他什么。 请指教。

这是来自org.scribe.model.Request class (Scribe library)

的代码
package org.scribe.model;

import java.io.*;
import java.net.*;
import java.nio.charset.*;
import java.util.*;
import java.util.concurrent.*;

import org.scribe.exceptions.*;

/**
 * Represents an HTTP Request object
 * 
 * @author Pablo Fernandez
 */
public class Request
{
  private static final String CONTENT_LENGTH = "Content-Length";
  private static final String CONTENT_TYPE = "Content-Type";
  private static RequestTuner NOOP = new RequestTuner() {
    @Override public void tune(Request _){}
  };
  public static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded";

  private String url;
  private Verb verb;
  private ParameterList querystringParams;
  private ParameterList bodyParams;
  private Map<String, String> headers;
  private String payload = null;
  private HttpURLConnection connection;
  private String charset;
  private byte[] bytePayload = null;
  private boolean connectionKeepAlive = false;
  private boolean followRedirects = true;
  private Long connectTimeout = null;
  private Long readTimeout = null;

  /**
   * Creates a new Http Request
   * 
   * @param verb Http Verb (GET, POST, etc)
   * @param url url with optional querystring parameters.
   */
  public Request(Verb verb, String url)
  {
    this.verb = verb;
    this.url = url;
    this.querystringParams = new ParameterList();
    this.bodyParams = new ParameterList();
    this.headers = new HashMap<String, String>();
  }

  /**
   * Execute the request and return a {@link Response}
   * 
   * @return Http Response
   * @throws RuntimeException
   *           if the connection cannot be created.
   */
  public Response send(RequestTuner tuner)
  {
    try
    {
      createConnection();
      return doSend(tuner);
    }
    catch (Exception e)
    {
      throw new OAuthConnectionException(e);
    }
  }

  public Response send()
  {
    return send(NOOP);
  }

  private void createConnection() throws IOException
  {
    String completeUrl = getCompleteUrl();
    if (connection == null)
    {
      System.setProperty("http.keepAlive", connectionKeepAlive ? "true" : "false");
      connection = (HttpURLConnection) new URL(completeUrl).openConnection();
      connection.setInstanceFollowRedirects(followRedirects);
    }
  }

  /**
   * Returns the complete url (host + resource + encoded querystring parameters).
   *
   * @return the complete url.
   */
  public String getCompleteUrl()
  {
    return querystringParams.appendTo(url);
  }

  Response doSend(RequestTuner tuner) throws IOException
  {
    connection.setRequestMethod(this.verb.name());
    if (connectTimeout != null) 
    {
      connection.setConnectTimeout(connectTimeout.intValue());
    }
    if (readTimeout != null)
    {
      connection.setReadTimeout(readTimeout.intValue());
    }
    addHeaders(connection);
    if (verb.equals(Verb.PUT) || verb.equals(Verb.POST))
    {
      addBody(connection, getByteBodyContents());
    }
    tuner.tune(this);
    return new Response(connection);
  }

  void addHeaders(HttpURLConnection conn)
  {
    for (String key : headers.keySet())
      conn.setRequestProperty(key, headers.get(key));
  }

  void addBody(HttpURLConnection conn, byte[] content) throws IOException
  {
    conn.setRequestProperty(CONTENT_LENGTH, String.valueOf(content.length));

    // Set default content type if none is set.
    if (conn.getRequestProperty(CONTENT_TYPE) == null)
    {
      conn.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
    }
    conn.setDoOutput(true);
    conn.getOutputStream().write(content);
  }

  /**
   * Add an HTTP Header to the Request
   * 
   * @param key the header name
   * @param value the header value
   */
  public void addHeader(String key, String value)
  {
    this.headers.put(key, value);
  }

  /**
   * Add a body Parameter (for POST/ PUT Requests)
   * 
   * @param key the parameter name
   * @param value the parameter value
   */
  public void addBodyParameter(String key, String value)
  {
    this.bodyParams.add(key, value);
  }

  /**
   * Add a QueryString parameter
   *
   * @param key the parameter name
   * @param value the parameter value
   */
  public void addQuerystringParameter(String key, String value)
  {
    this.querystringParams.add(key, value);
  }

  /**
   * Add body payload.
   * 
   * This method is used when the HTTP body is not a form-url-encoded string,
   * but another thing. Like for example XML.
   * 
   * Note: The contents are not part of the OAuth signature
   * 
   * @param payload the body of the request
   */
  public void addPayload(String payload)
  {
    this.payload = payload;
  }

  /**
   * Overloaded version for byte arrays
   *
   * @param payload
   */
  public void addPayload(byte[] payload)
  {
    this.bytePayload = payload.clone();
  }

  /**
   * Get a {@link ParameterList} with the query string parameters.
   * 
   * @return a {@link ParameterList} containing the query string parameters.
   * @throws OAuthException if the request URL is not valid.
   */
  public ParameterList getQueryStringParams()
  {
    try
    {
      ParameterList result = new ParameterList();
      String queryString = new URL(url).getQuery();
      result.addQuerystring(queryString);
      result.addAll(querystringParams);
      return result;
    }
    catch (MalformedURLException mue)
    {
      throw new OAuthException("Malformed URL", mue);
    }
  }

  /**
   * Obtains a {@link ParameterList} of the body parameters.
   * 
   * @return a {@link ParameterList}containing the body parameters.
   */
  public ParameterList getBodyParams()
  {
    return bodyParams;
  }

  /**
   * Obtains the URL of the HTTP Request.
   * 
   * @return the original URL of the HTTP Request
   */
  public String getUrl()
  {
    return url;
  }

  /**
   * Returns the URL without the port and the query string part.
   * 
   * @return the OAuth-sanitized URL
   */
  public String getSanitizedUrl()
  {
    return url.replaceAll("\\?.*", "").replace("\\:\\d{4}", "");
  }

  /**
   * Returns the body of the request
   * 
   * @return form encoded string
   * @throws OAuthException if the charset chosen is not supported
   */
  public String getBodyContents()
  {
    try
    {
      return new String(getByteBodyContents(),getCharset());
    }
    catch(UnsupportedEncodingException uee)
    {
      throw new OAuthException("Unsupported Charset: "+charset, uee);
    }
  }

  byte[] getByteBodyContents()
  {
    if (bytePayload != null) return bytePayload;
    String body = (payload != null) ? payload : bodyParams.asFormUrlEncodedString();
    try
    {
      return body.getBytes(getCharset());
    }
    catch(UnsupportedEncodingException uee)
    {
      throw new OAuthException("Unsupported Charset: "+getCharset(), uee);
    }
  }

  /**
   * Returns the HTTP Verb
   * 
   * @return the verb
   */
  public Verb getVerb()
  {
    return verb;
  }

  /**
   * Returns the connection headers as a {@link Map}
   * 
   * @return map of headers
   */
  public Map<String, String> getHeaders()
  {
    return headers;
  }

  /**
   * Returns the connection charset. Defaults to {@link Charset} defaultCharset if not set
   *
   * @return charset
   */
  public String getCharset()
  {
    return charset == null ? Charset.defaultCharset().name() : charset;
  }

  /**
   * Sets the connect timeout for the underlying {@link HttpURLConnection}
   * 
   * @param duration duration of the timeout
   * 
   * @param unit unit of time (milliseconds, seconds, etc)
   */
  public void setConnectTimeout(int duration, TimeUnit unit)
  {
    this.connectTimeout = unit.toMillis(duration);
  }

  /**
   * Sets the read timeout for the underlying {@link HttpURLConnection}
   * 
   * @param duration duration of the timeout
   * 
   * @param unit unit of time (milliseconds, seconds, etc)
   */
  public void setReadTimeout(int duration, TimeUnit unit)
  {
    this.readTimeout = unit.toMillis(duration);
  }

  /**
   * Set the charset of the body of the request
   *
   * @param charsetName name of the charset of the request
   */
  public void setCharset(String charsetName)
  {
    this.charset = charsetName;
  }

  /**
   * Sets whether the underlying Http Connection is persistent or not.
   *
   * @see http://download.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html
   * @param connectionKeepAlive
   */
  public void setConnectionKeepAlive(boolean connectionKeepAlive)
  {
    this.connectionKeepAlive = connectionKeepAlive;
  }

  /**
   * Sets whether the underlying Http Connection follows redirects or not.
   *
   * Defaults to true (follow redirects)
   *
   * @see http://docs.oracle.com/javase/6/docs/api/java/net/HttpURLConnection.html#setInstanceFollowRedirects(boolean)
   * @param followRedirects
   */
  public void setFollowRedirects(boolean followRedirects)
  {
    this.followRedirects = followRedirects;
  }

  /*
   * We need this in order to stub the connection object for test cases
   */
  void setConnection(HttpURLConnection connection)
  {
    this.connection = connection;
  }

  @Override
  public String toString()
  {
    return String.format("@Request(%s %s)", getVerb(), getUrl());
  }
}

1 个答案:

答案 0 :(得分:2)

当我挣扎时,这个错误几乎让我疯狂,我(想)通过对我的代码进行微小的改动来解决问题。希望它也能帮到你。

  1. 如果您的httpurlconnection请求是POST请求,请删除此行conn.setDoOutput(true);

  2. 在获取对conn.connect()

  3. 的outputStream调用之前
  4. 最后,我完全删除了http.keepAlive

  5. 到目前为止没有更多的随机EOF(因为我上周改变了它)。