【问题标题】:Android HttpURLConnection receives HTTP 301 response codeAndroid HttpURLConnection 收到 HTTP 301 响应码
【发布时间】:2017-02-12 05:44:23
【问题描述】:

我正在尝试使用 Android 中的 HttpURLConnection 对象进行 HTTP GET。

更新

我尝试连接到不同的服务器。这也托管在 Cloud 9 (c9.io) 中,并且还返回一个 json 响应。这次我没有收到 301 重定向,但我收到了服务器应该发送的实际响应。

由于这意味着问题发生在服务器内部,因此我重新组织了以下部分,以便重点阅读与服务器相关的信息。 Android 相关信息已移至问题末尾。

我在哪里连接:

  • Cloud9 上的开发服务器
  • 使用 Laravel Framework 5.2(由于项目依赖项不受支持,我们目前无法升级到 5.3)
  • 服务器应返回 JSON 答案
  • 如果我通过浏览器连接到同一个 URL,我会得到正确的响应(JSON 字符串。必需的 HTTP 标头和“200”HTTP 响应代码)

我从哪里连接

  • Android 手机(一加 3,Android 6.0)
  • 编译SDK版本:23
  • 使用构建工具:“23.0.3”
  • 使用 Min SDK 版本:19
  • 使用目标 SDK 版本:22
  • 我正在使用 HttpURLConnection 对象进行连接,使用 HTTP 方法“GET”

Android 上的 HTTP 响应

当我运行我的代码时,我会从服务器获得以下结果:

HTTP 响应代码是 301,但消息是 null。

  1. 新的 URL 完全相同,但使用的是 HTTPS。似乎服务器以某种方式强制 SSL/TSL 加密。从浏览器访问 HTTP 时不会发生这种情况。

HTTP 标头(在 Android 上):

  • 日期 => 2016 年 10 月 4 日星期二 05:56:26 GMT
  • location => https://domain.com/route/(我修改了这个位)
  • 内容长度 => 382
  • 内容类型 => 文本/html; charset=iso-8859-1
  • X-BACKEND => 应用代理
  • X-Android-Selected-Protocol => http/1.1
  • X-Android-Sent-Millis => 1475560583894
  • X-Android-Received-Millis => 1475560585637
  • X-Android-Response-Source => 网络 301
  • null => HTTP/1.1 301

其他数据

  1. 由于服务器似乎希望 Android 使用 HTTPS,我尝试修改代码以使用 HTTPS (HttpsURLConnection)。这可能会也可能不会解决 this 问题,但我无法检查它,因为我收到了一个恼人的 SSL handshake failed 错误。另外,我不需要对此应用程序进行加密,因此我不愿意解决随之而来的问题。
  2. 这一切都在 AsyncTask 对象中运行(因为当您尝试在主线程上使用网络连接时,Android 会变得喜怒无常)。
  3. 设置新服务器(在 Cloud 9 之外且没有任何 SSL/TSL)可能是一种选择,但我不愿意这样做,因为这会非常耗时。
  4. 我尝试使用完全相同的代码连接到另一个 Cloud 9 服务器(它也返回一个 json 响应),并且一切正常。这表明问题是由 HTPP 301 错误引起的。

我将尝试与您分享您回答我的问题可能需要的任何其他信息!

原生 Android 东西(在 UPDATE 上移动,见上文)

响应内容似乎是一个不完整 JSON:

{ 'status':'ERROR'

注意我没有忘记结束 } 字符,这就是响应实际包含的内容。这是在工作流程中(对我而言)未知的地方注入的。当我捕获 HTTP 响应(在我的 PC 上使用 Charles,它被设置为我手机 Wi-Fi 连接的代理)时,它的内容(如预期的那样)是一个简单的 HTML,告诉您重定向(HTPP 代码 301)到新路由.

不存在无效的 JSON 代码(上图),但存在 有效的 HTML。

这表明无效的 JSON 出现在我的代码内部某处(而不是在服务器或传输中)。但是我的应用程序上没有生成 JSON 字符串的代码,更不用说将其注入我正在处理的响应中了。

HttpURLConnection 的代码

this.setURL(ruta); //gets correct url
HttpURLConnection cxn = (HttpURLConnection) this.getURL().openConnection(); //init
cxn.setRequestMethod("GET"); //use HTTP GET verb
cxn.setUseCaches(false); //no cache
cxn.setRequestProperty("Cache-Control", "no-cache"); //even less cache
cxn.setDoOutput(false); //only true in POST/PUT requests
cxn.setRequestProperty("Connection","keep-alive");
cxn.setRequestProperty("DNT", "1"); //TEMP
cxn.setInstanceFollowRedirects(true); //should follow redirects
cxn.setRequestProperty( "charset", "utf-8");

读取结果的代码

int status_code = cxn.getResponseCode();
InputStream responseStream = new BufferedInputStream(cxn.getInputStream());
BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(responseStream));
String line = "";
StringBuilder stringBuilder = new StringBuilder();
while ((line = responseStreamReader.readLine()) != null) {
    stringBuilder.append(line).append("\n");
}
responseStreamReader.close();
String response = stringBuilder.toString();
cxn.disconnect();

【问题讨论】:

  • "Content-Type", "application/x-www-form-urlencoded"); ????对于 GET 请求?我建议也删除所有其他请求属性。
  • 在接收正确数据时遇到问题,我希望您发布阅读它的代码。但你没有。
  • 刚刚添加了代码,问题结束。仍然(正如我在上一次更新中解释的那样)我可以从其他服务器接收正确的数据。 @greenapps
  • @greenapps 你对 content-type 属性是正确的。我添加了它,因为它出现在浏览器发送的标题上,但我再次检查它并不存在(我可能读错了)。我删除了它。可悲的是,这并没有解决任何问题
  • GET 和 doOutput(false) 和 Connection: keep-alive 是默认值。不要编写无意义的代码。

标签: java android json laravel http-status-code-301


【解决方案1】:

我遇到了同样的问题,我在阅读 this source 后修复了它。
我们需要做的就是处理如下所示的 3** 个错误

if(responseCode > 300 && responseCode < 400) {

    String redirectHeader = conn.getHeaderField("Location");
    if(TextUtils.isEmpty(redirectHeader)) {                       
        return new JsonResponse(responseCode, "Failed to redirect");
    }
    JsonRequest newRequest = request;
    newRequest.url = redirectHeader;
    return getJsonFromUrl(newRequest);
}

每个 3** 响应都应该有一个名为 Location 的标题,其中包含我们应该使用的重定向链接。

【讨论】:

    【解决方案2】:

    换行: HttpURLConnection cxn = (HttpURLConnection) this.getURL().openConnection();

    与: HttpsURLConnection cxn = (HttpsURLConnection) this.getURL().openConnection();

    这样你就可以处理 https

    【讨论】:

      【解决方案3】:

      将协议更改为 https 对我有用。

      【讨论】:

      • 该解决方案仅在您拥有安全的 https 服务器时才有效,而目前我没有。不过,它是有效的。
      【解决方案4】:

      删除您用于创建HttpURLConnection 的代码并尝试使用此代码:

      URL url;
      HttpURLConnection urlConnection = null;
      try {
          url = new URL("http://www.domain.com/index.aspx?parameter1=X&parameter2=X"); //Use your url and add the GET parameters
      
          urlConnection = (HttpURLConnection) url.openConnection();
      
          urlConnection.setInstanceFollowRedirects(false); /* added line */
      
          InputStream in = urlConnection.getInputStream();
      
          InputStreamReader isw = new InputStreamReader(in);
      
          int data = isw.read();
          while (data != -1) {
              char current = (char) data;
              data = isw.read();
              System.out.print(current);
          }
      } catch (Exception e) {
          e.printStackTrace();
      } finally {
          if (urlConnection != null) {
              urlConnection.disconnect();
          }    
      }
      

      这应该是您为GET 请求设置的全部内容。

      编辑:

      我已经使用Volley 测试了网络服务,这是我用来检索网络服务响应的代码:

      public class MainActivity extends AppCompatActivity {
      
        public String response;
        TextView textView;
      
        @Override
        protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
      
          textView = (TextView) findViewById(R.id.rTextView);
      
          RequestQueue queue = Volley.newRequestQueue(this);
          String url = "yourWebserviceUrl";
      
          // Request a string response from the provided URL. 
          StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener < String > () {
              @Override
              public void onResponse(String response) {
                textView.setText("Response is: " + response);
              }
            }, new Response.ErrorListener() {
              @Override
              public void onErrorResponse(VolleyError error) {
                textView.setText("That didn't work!");
              }
            });
          // Add the request to the RequestQueue. 
          queue.add(stringRequest);
      
        }
      
      }
      

      这是我得到的回复:

      {"status":"ok","found":false,"extra":"App\\Scanners"}
      

      【讨论】:

      • 今天我已经关闭了我的电脑。不过我会在几个小时内试试这个! (截止日期越来越近了)
      • @PabloKvitca 希望它有效! :) 如果您发现代码有任何问题,请告诉我!
      • 我试过了,代码运行正常。但问题仍然存在。我仍然收到来自服务器的无法解释的 HTTP 301 响应
      • @PabloKvitca 真的很奇怪,你可以试试我上面发布的编辑代码吗?我刚刚在打开连接之前将setInstanceFollowRedirects 添加到false
      • 我会试试的。但是 url.openConnection() 不会覆盖我之前设置的任何内容吗?我相信这应该在那一点之后。不管怎样,我正在尝试你写的
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-09
      • 2022-01-27
      • 2015-08-25
      • 1970-01-01
      相关资源
      最近更新 更多