Thực hiện một yêu cầu HTTP với Android


352

Tôi đã tìm kiếm khắp nơi nhưng tôi không thể tìm thấy câu trả lời của mình, có cách nào để thực hiện một yêu cầu HTTP đơn giản không? Tôi muốn yêu cầu một trang / tập lệnh PHP trên một trong các trang web của mình nhưng tôi không muốn hiển thị trang web.

Nếu có thể tôi thậm chí muốn làm điều đó trong nền (trong BroadcastReceiver)


Câu trả lời:


477

CẬP NHẬT

Đây là một câu trả lời rất cũ. Tôi chắc chắn sẽ không đề xuất khách hàng của Apache nữa. Thay vào đó sử dụng một trong hai:

Câu trả lời gốc

Trước hết, yêu cầu quyền truy cập mạng, thêm thông tin sau vào bảng kê khai của bạn:

<uses-permission android:name="android.permission.INTERNET" />

Sau đó, cách dễ nhất là sử dụng máy khách Apache http đi kèm với Android:

    HttpClient httpclient = new DefaultHttpClient();
    HttpResponse response = httpclient.execute(new HttpGet(URL));
    StatusLine statusLine = response.getStatusLine();
    if(statusLine.getStatusCode() == HttpStatus.SC_OK){
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        response.getEntity().writeTo(out);
        String responseString = out.toString();
        out.close();
        //..more logic
    } else{
        //Closes the connection.
        response.getEntity().getContent().close();
        throw new IOException(statusLine.getReasonPhrase());
    }

Nếu bạn muốn nó chạy trên luồng riêng biệt, tôi khuyên bạn nên mở rộng AsyncTask:

class RequestTask extends AsyncTask<String, String, String>{

    @Override
    protected String doInBackground(String... uri) {
        HttpClient httpclient = new DefaultHttpClient();
        HttpResponse response;
        String responseString = null;
        try {
            response = httpclient.execute(new HttpGet(uri[0]));
            StatusLine statusLine = response.getStatusLine();
            if(statusLine.getStatusCode() == HttpStatus.SC_OK){
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                response.getEntity().writeTo(out);
                responseString = out.toString();
                out.close();
            } else{
                //Closes the connection.
                response.getEntity().getContent().close();
                throw new IOException(statusLine.getReasonPhrase());
            }
        } catch (ClientProtocolException e) {
            //TODO Handle problems..
        } catch (IOException e) {
            //TODO Handle problems..
        }
        return responseString;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        //Do anything with response..
    }
}

Sau đó, bạn có thể thực hiện một yêu cầu bằng cách:

   new RequestTask().execute("http://stackoverflow.com");

11
Đây là một bài viết từ blog nhà phát triển Android chính thức trên AsyncTask: android-developers.blogspot.com/2010/07/ Kẻ
Austyn Mahoney

77
cho gừng hoặc cao hơn nó thực sự khuyên nên sử dụng HttpURLConnection trên thư viện apache, xem android-developers.blogspot.com/2011/09/... . Nó ít đánh thuế vào pin hơn và có hiệu suất tốt hơn
Marty

8
answerString = out.toString () cần có trước cuộc gọi out.close (). Trên thực tế, có lẽ bạn nên có out.close () trong một khối cuối cùng. Nhưng nhìn chung, câu trả lời rất hữu ích (+1), cảm ơn!
dcp

9
Kể từ Honeycomb (SDK 11), cách tiếp cận không đồng bộ là hướng đi. Một NetworkOnMainThreadException bị ném khi bạn cố gắng chạy một yêu cầu HTTP từ các chủ đề chính.
msrxthr

2
Câu trả lời này khá xuất sắc. Nhưng tôi sẽ khuyên không nên sử dụng AsyncT task cho Mạng. Họ có thể tạo rò rỉ bộ nhớ rất dễ dàng (và thực tế là ví dụ được cung cấp bị rò rỉ) và không cung cấp tất cả các tính năng mà người ta có thể mong đợi cho các yêu cầu mạng. Cân nhắc sử dụng RoboSpice cho loại tác vụ nền này: github.com/octo-online/robospice
Snicolas

67

trừ khi bạn có một lý do rõ ràng để chọn ApacheClClient, bạn nên chọn java.net.URLCconnect. bạn có thể tìm thấy rất nhiều ví dụ về cách sử dụng nó trên web.

chúng tôi cũng đã cải thiện tài liệu Android kể từ bài đăng gốc của bạn: http://developer.android.com/reference/java/net/HttpURLConnection.html

và chúng tôi đã nói về sự đánh đổi trên blog chính thức: http://android-developers.blogspot.com/2011/09/androids-http-clents.html


13
Tại sao không nên sử dụng Apache HTTPClient?
Ted

4
Một người đồng mưu của tôi đã đi sâu vào vấn đề này rất chi tiết trên blog chính thức: android-developers.blogspot.com/2011/09/ Kẻ
Elliott Hughes

@ElliottHughes: Tôi đồng ý 100%. Không thể phủ nhận rằng Apache httpclient cung cấp các phương thức dễ dàng và một cái nhìn trừu tượng hơn về giao thức, nhưng urlconnection của java hoàn toàn không hữu ích. Với một chút thực hành, nó dễ sử dụng như httpclient và dễ mang theo hơn
Nitin Bansal

1
Trên thực tế nếu bạn xem video Google I / O 2010 - các ứng dụng khách Android REST ( youtube.com/watch?v=xHXn3Kg2IQE 57min21sec), bạn sẽ thấy Apache httpClient là ứng dụng được khuyên dùng nhất. Tôi trích dẫn Virgil Dobjanschi (một kỹ sư phần mềm trên google hoạt động trên Nhóm ứng dụng Android) "Tôi chỉ đơn giản khuyên bạn nên sử dụng máy khách HTTP Apache, bởi vì nó có triển khai mạnh mẽ hơn. Loại kết nối URL của giao dịch HTTP không hiệu quả nhất triển khai. Và cách nó chấm dứt các kết nối đôi khi có thể có ảnh hưởng xấu đến mạng. "
Alan

46

Lưu ý: Máy khách HTTP Apache đi kèm với Android hiện không được hỗ trợ cho kết nối httpURLC . Vui lòng xem Blog Nhà phát triển Android để biết thêm chi tiết.

Thêm <uses-permission android:name="android.permission.INTERNET" />vào bảng kê khai của bạn.

Sau đó, bạn sẽ lấy một trang web như vậy:

URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
     readStream(in);
}
finally {
     urlConnection.disconnect();
}

Tôi cũng đề nghị chạy nó trên một chủ đề riêng biệt:

class RequestTask extends AsyncTask<String, String, String>{

@Override
protected String doInBackground(String... uri) {
    String responseString = null;
    try {
        URL url = new URL(myurl);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if(conn.getResponseCode() == HttpsURLConnection.HTTP_OK){
            // Do normal input or output stream reading
        }
        else {
            response = "FAILED"; // See documentation for more info on response handling
        }
    } catch (ClientProtocolException e) {
        //TODO Handle problems..
    } catch (IOException e) {
        //TODO Handle problems..
    }
    return responseString;
}

@Override
protected void onPostExecute(String result) {
    super.onPostExecute(result);
    //Do anything with response..
}
}

Xem tài liệu để biết thêm thông tin về xử lý phản hồi và yêu cầu POST.


1
@Semmix Làm sao vậy? Câu hỏi yêu cầu "một HTTP đơn giản" và mã của tôi thực hiện chính xác điều đó.
kevinc

1
Tôi hiểu rằng khối mã đầu tiên của bạn được sao chép từ các tài liệu Android, nhưng con người là rác mẫu / tài liệu đó. readStreamthậm chí không được xác định.
Eugene K

@EugeneK Họ là, nhưng đây có lẽ là cách đơn giản nhất để trả lời câu hỏi này. Thực hiện một Yêu cầu HTTP đúng cách trong Android sẽ liên quan đến việc giải thích Retrofit và OkHttp. Tôi nghĩ rằng điều đó sẽ gây nhầm lẫn cho người mới bắt đầu hơn là chỉ đưa ra một đoạn mã về mặt kỹ thuật sẽ thực hiện một yêu cầu HTTP đơn giản, ngay cả khi nó được xây dựng kém.
kevinc

12

Cách đơn giản nhất là sử dụng lib Android có tên là Volley

Volley cung cấp các lợi ích sau:

Lập lịch tự động các yêu cầu mạng. Nhiều kết nối mạng đồng thời . Bộ nhớ đệm đáp ứng bộ nhớ và đĩa trong suốt với sự kết hợp bộ đệm HTTP tiêu chuẩn. Hỗ trợ ưu tiên yêu cầu. API yêu cầu hủy. Bạn có thể hủy một yêu cầu hoặc bạn có thể đặt các khối hoặc phạm vi yêu cầu để hủy. Dễ tùy chỉnh, ví dụ, để thử lại và backoff. Thứ tự mạnh mẽ giúp dễ dàng điền chính xác giao diện người dùng của bạn với dữ liệu được tìm nạp không đồng bộ từ mạng. Công cụ gỡ lỗi và truy tìm.

Bạn có thể gửi yêu cầu http / https đơn giản như sau:

        // Instantiate the RequestQueue.
        RequestQueue queue = Volley.newRequestQueue(this);
        String url ="http://www.yourapi.com";
        JsonObjectRequest request = new JsonObjectRequest(url, null,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    if (null != response) {
                         try {
                             //handle your response
                         } catch (JSONException e) {
                             e.printStackTrace();
                         }
                    }
                }
            }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {

            }
        });
        queue.add(request);

Trong trường hợp này, bạn không cần phải xem xét "chạy trong nền" hoặc "sử dụng bộ đệm" vì tất cả những điều này đã được Volley thực hiện.


6
private String getToServer(String service) throws IOException {
    HttpGet httpget = new HttpGet(service);
    ResponseHandler<String> responseHandler = new BasicResponseHandler();
    return new DefaultHttpClient().execute(httpget, responseHandler);

}

Trân trọng


4

Với một chủ đề:

private class LoadingThread extends Thread {
    Handler handler;

    LoadingThread(Handler h) {
        handler = h;
    }
    @Override
    public void run() {
        Message m = handler.obtainMessage();
        try {
            BufferedReader in = 
                new BufferedReader(new InputStreamReader(url.openStream()));
            String page = "";
            String inLine;

            while ((inLine = in.readLine()) != null) {
                page += inLine;
            }

            in.close();
            Bundle b = new Bundle();
            b.putString("result", page);
            m.setData(b);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        handler.sendMessage(m);
    }
}

4

Tôi đã thực hiện điều này cho một dịch vụ web để yêu cầu URL, sử dụng lib Gson:

Khách hàng:

public EstabelecimentoList getListaEstabelecimentoPorPromocao(){

        EstabelecimentoList estabelecimentoList  = new EstabelecimentoList();
        try{
            URL url = new URL("http://" +  Conexao.getSERVIDOR()+ "/cardapio.online/rest/recursos/busca_estabelecimento_promocao_android");
            HttpURLConnection con = (HttpURLConnection) url.openConnection();

            if (con.getResponseCode() != 200) {
                    throw new RuntimeException("HTTP error code : "+ con.getResponseCode());
            }

            BufferedReader br = new BufferedReader(new InputStreamReader((con.getInputStream())));
            estabelecimentoList = new Gson().fromJson(br, EstabelecimentoList.class);
            con.disconnect();

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

4

Nhìn vào thư viện mới tuyệt vời này có sẵn thông qua gradle :)

bản dựng. compile 'com.apptakk.http_request:http-request:0.1.2'

Sử dụng:

new HttpRequestTask(
    new HttpRequest("http://httpbin.org/post", HttpRequest.POST, "{ \"some\": \"data\" }"),
    new HttpRequest.Handler() {
      @Override
      public void response(HttpResponse response) {
        if (response.code == 200) {
          Log.d(this.getClass().toString(), "Request successful!");
        } else {
          Log.e(this.getClass().toString(), "Request unsuccessful: " + response);
        }
      }
    }).execute();

https://github.com/erf/http-request


1
Có vẻ như mọi thư viện khác ...
Nick Gallzar

3

Sử dụng Volley như đề xuất ở trên. Thêm phần sau vào build.gradle (Module: ứng dụng)

implementation 'com.android.volley:volley:1.1.1'

Thêm phần sau vào AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

Và thêm sau đây cho bạn Mã hoạt động:

public void httpCall(String url) {

    RequestQueue queue = Volley.newRequestQueue(this);

    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    // enjoy your response
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    // enjoy your error status
                }
    });

    queue.add(stringRequest);
}

Nó thay thế http client và nó rất đơn giản.


2

Đây là mã mới cho yêu cầu Nhận / POST HTTP trong Android. HTTPClientbị lỗi thời và có thể không có sẵn như trong trường hợp của tôi.

Đầu tiên, thêm hai phụ thuộc trong build.gradle:

compile 'org.apache.httpcomponents:httpcore:4.4.1'
compile 'org.apache.httpcomponents:httpclient:4.5'

Sau đó viết mã này ASyncTasktrong doBackgroundphương thức.

 URL url = new URL("http://localhost:8080/web/get?key=value");
 HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
 urlConnection.setRequestMethod("GET");
 int statusCode = urlConnection.getResponseCode();
 if (statusCode ==  200) {
      InputStream it = new BufferedInputStream(urlConnection.getInputStream());
      InputStreamReader read = new InputStreamReader(it);
      BufferedReader buff = new BufferedReader(read);
      StringBuilder dta = new StringBuilder();
      String chunks ;
      while((chunks = buff.readLine()) != null)
      {
         dta.append(chunks);
      }
 }
 else
 {
     //Handle else
 }

Mã có thể bị phản đối và apache không còn được hỗ trợ trong API nền tảng Android 28. Trong trường hợp đó, bạn có thể kích hoạt thuộc tính kế thừa apache trong tệp Cấp độ mô-đun hoặc cấp độ mô-đun. Tuy nhiên, nên sử dụng thư viện mạng OKHttp, Volley hoặc Retrofit.
Rahul Raina

1

Đối với tôi, cách dễ nhất là sử dụng thư viện có tên Retrofit2

Chúng tôi chỉ cần tạo Giao diện chứa phương thức yêu cầu, tham số và chúng tôi cũng có thể tạo tiêu đề tùy chỉnh cho từng yêu cầu:

    public interface MyService {

      @GET("users/{user}/repos")
      Call<List<Repo>> listRepos(@Path("user") String user);

      @GET("user")
      Call<UserDetails> getUserDetails(@Header("Authorization") String   credentials);

      @POST("users/new")
      Call<User> createUser(@Body User user);

      @FormUrlEncoded
      @POST("user/edit")
      Call<User> updateUser(@Field("first_name") String first, 
                            @Field("last_name") String last);

      @Multipart
      @PUT("user/photo")
      Call<User> updateUser(@Part("photo") RequestBody photo, 
                            @Part("description") RequestBody description);

      @Headers({
        "Accept: application/vnd.github.v3.full+json",
        "User-Agent: Retrofit-Sample-App"
      })
      @GET("users/{username}")
      Call<User> getUser(@Path("username") String username);    

    }

Và tốt nhất là, chúng ta có thể thực hiện nó một cách không đồng bộ một cách dễ dàng bằng phương pháp enqueue


1

Vì không có câu trả lời nào mô tả cách thực hiện các yêu cầu với OkHttp , ứng dụng http rất phổ biến hiện nay cho Android và Java nói chung, tôi sẽ cung cấp một ví dụ đơn giản:

//get an instance of the client
OkHttpClient client = new OkHttpClient();

//add parameters
HttpUrl.Builder urlBuilder = HttpUrl.parse("https://www.example.com").newBuilder();
urlBuilder.addQueryParameter("query", "stack-overflow");


String url = urlBuilder.build().toString();

//build the request
Request request = new Request.Builder().url(url).build();

//execute
Response response = client.newCall(request).execute();

Ưu điểm rõ ràng của thư viện này là nó trừu tượng hóa chúng ta từ một số chi tiết cấp thấp, cung cấp các cách thân thiện và an toàn hơn để tương tác với chúng. Cú pháp cũng được đơn giản hóa và cho phép viết mã đẹp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.