laravel Android HttpURLConnection 接收 HTTP 301 响应代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39845854/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 14:33:20  来源:igfitidea点击:

Android HttpURLConnection receives HTTP 301 response code

javaandroidjsonlaravelhttp-status-code-301

提问by Pablo Kvitca

I'm trying to do a HTTP GET using the HttpURLConnection object in Android.

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

UPDATE

更新

I tried connection to a different server. This is also hosted within Cloud 9 (c9.io) and also returns a json response. This time I'm notgetting a 301 redirect, but I am getting the actual response the server is supposed to send.

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

Since this means the problem is localised within the server, I've reorganized the following sections in order to focus reading onto the server-related information. Android related information has been moved to the end of the question.

由于这意味着问题是在服务器中本地化的,因此我重新组织了以下部分,以便将重点放在与服务器相关的信息上。Android 相关信息已移至问题末尾。

Where I am connecting:

我在哪里连接:

  • Development server on Cloud9
  • Using the Laravel Framework 5.2 (we cannot upgrade to 5.3 at this time, due to unsupported project dependencies)
  • The server should return a JSON answer
  • If I connect to the same URL through the browser I get the correct response (JSON string. Required HTTP Headers and a '200' HTTP Response Code)
  • Cloud9上的开发服务器
  • 使用 Laravel Framework 5.2(由于不支持的项目依赖,我们目前无法升级到 5.3)
  • 服务器应该返回一个 JSON 答案
  • 如果我通过浏览器连接到相同的 URL,我会得到正确的响应(JSON 字符串。必需的 HTTP 标头和“200”HTTP 响应代码)

Where I am connecting FROM

我在哪里连接 FROM

  • Android phone (Oneplus 3, on Android 6.0)
  • Compile SDK version: 23
  • Using Build Tools: "23.0.3"
  • Using Min SDK verion: 19
  • Using Target SDK version: 22
  • I'm connectiong using a HttpURLConnection object, using HTTP Method 'GET'
  • Android 手机(一加 3,Android 6.0)
  • 编译SDK版本:23
  • 使用构建工具:“23.0.3”
  • 使用最小 SDK 版本:19
  • 使用目标 SDK 版本:22
  • 我正在使用 HttpURLConnection 对象进行连接,使用 HTTP 方法“GET”

HTTP Response on Android

Android 上的 HTTP 响应

When I run my code I get the folling result from the server:

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

The HTTP response code is 301but the message is null.

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

  1. The new URL is exactly the same, but using HTTPS. It seems server is somehow forcing SSL/TSL encryption. Which does nothappen when accessing HTTP from the browser.
  1. 新 URL 完全相同,但使用 HTTPS。似乎服务器以某种方式强制 SSL/TSL 加密。这确实不是从浏览器访问HTTP时发生。

HTTP Header (on Android):

HTTP 标头(在 Android 上):

  • date => Tue, 04 Oct 2016 05:56:26 GMT
  • location => https://domain.com/route/(I modified this bit)
  • content-length => 382
  • content-type => text/html; charset=iso-8859-1
  • X-BACKEND => apps-proxy
  • X-Android-Selected-Protocol => http/1.1
  • X-Android-Sent-Millis => 1475560583894
  • X-Android-Received-Millis => 1475560585637
  • X-Android-Response-Source => NETWORK 301
  • null => HTTP/1.1 301
  • 日期 => 2016 年 10 月 4 日星期二 05:56:26 GMT
  • 位置 => https://domain.com/route/(我修改了这一点)
  • 内容长度 => 382
  • 内容类型 => 文本/html;字符集=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
  • 空 => HTTP/1.1 301

Other data

其他数据

  1. Since it seems the server wants Android to use HTTPS, I tried modifying the code to use HTTPS (HttpsURLConnection). This may or may not solve thisproblem, but I am unable to check it since I get an annoying SSL handshake failederror. Plus I have no need for encryption on this application, and therefore I'm reluctant to solve the problems coming with it.
  2. This is all running within an AsyncTask object (since Android get moody when you try to use a network connection on the main thread).
  3. Setting up a new server (outside of Cloud 9 and without any SSL/TSL) could be an option, but I'm reluctant to do this since it would be quite time consuming.
  4. I tried connecting to another Cloud 9 server (which also returns a json response), using the exact same code, and everything works correctly. This suggests that the problem arises from the HTPP 301 error.
  1. 由于服务器似乎希望Android使用HTTPS,因此我尝试修改代码以使用HTTPS(HttpsURLConnection)。这可能会也可能不会解决这个问题,但我无法检查它,因为我遇到了一个烦人的SSL handshake failed错误。另外我不需要在这个应用程序上加密,因此我不愿意解决它带来的问题。
  2. 这一切都在 AsyncTask 对象中运行(因为当您尝试在主线程上使用网络连接时,Android 会变得情绪化)。
  3. 设置新服务器(在 Cloud 9 之外且没有任何 SSL/TSL)可能是一种选择,但我不愿意这样做,因为这会非常耗时。
  4. 我尝试连接到另一个 Cloud 9 服务器(它也返回一个 json 响应),使用完全相同的代码,一切正常。这表明问题出自 HTPP 301 错误。

I will try to share with you any other information you may require to answer my question!

我会尽量与您分享您可能需要的任何其他信息来回答我的问题!

Native Android stuff (moved on UPDATE, see above)

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

The response content seemsto be an incompleteJSON:

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

{ 'status':'ERROR'

Note I did NOT forget the closing }character, that's what the response actually containts. This is injected somewhere unknown (to me) during the workflow. When I capture the HTTP response (using Charles on my PC, which is set as a Proxy for my phone's Wi-Fi connection) it's content is (as expected) a simple HTML telling you to redirect (HTPP code 301) to a new route.

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

The invalid JSON code (above) isn't there, but a validHTML is.

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

This would suggest that the invalid JSON appears somewhere internally to my code (not on the server, or transport). But there is no code on my app that generates a JSON string, let alone inject it into the response I'm processing.

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

Code for the HttpURLConnection

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");

Code for the reading the result

读取结果的代码

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();

回答by LS_

Remove the code you've used to create the HttpURLConnectionand try with this one:

删除您用于创建的代码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();
    }    
}

This should be all you need to set for your GETrequest.

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

EDIT:

编辑:

I've tested the webservice using Volley, here's the code I've used in order to retrieve the webservice response:

我已经使用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);

  }

}

And this is the response I got:

这是我得到的回应:

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

回答by Kostya M

I faced the same problem, and I fixed it after reading this source.
All we need to do is handling 3** errors like shown below

我遇到了同样的问题,并在阅读此来源后修复了它。
我们需要做的就是处理 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);
}

Each 3** response should have a header with name Locationwhich contains a redirect link which we should use.

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

回答by Jozsef Lehocz

Changing the protocol to https worked for me.

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

回答by Harry Cotte

Change the line : HttpURLConnection cxn = (HttpURLConnection) this.getURL().openConnection();

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

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

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

So you will able to handle https

所以你将能够处理https