2012-05-25 2 views
0

У меня есть несколько автоматических тестов, которые используют HttpURLConnection для реализации RESTful API.HttpURLConnection.getResponseCode не подбирает HTTP-код ответа 206

Часть моего кода (ниже) утверждает, что ответ возвращает определенный код ответа HTTP. Я ожидаю HTTP 206 Response, но getResponseCode всегда возвращает 200. Однако, если я ударил url напрямую с помощью curl, я получаю «HTTP/1.1 206 Partial Content», как и ожидалось.

URL requestURL = new URL(url); 
    HttpURLConnection connection = (HttpURLConnection) requestURL.openConnection(); 
    try { 
     connection.setRequestProperty("Connection", "close"); 
     connection.setReadTimeout(5000); 

     assertEquals("Request successfully handled", 
       expectedResponseCode, 
       connection.getResponseCode()); 

     InputStream input = connection.getInputStream(); 
     try { 
      return toString(input); 
     } finally { 
      input.close(); 
     } 
    } finally { 
     connection.disconnect(); 
    } 

Любые идеи о том, почему это происходит и как получить поведение, которое я хочу?

ответ

1

Таким образом, проблема заключалась в том, что я вызывал write() перед установкой кода ответа. Хотя это, похоже, работает при использовании с curl, оно не работает с модульными тестами, поскольку код подтверждает код возврата сразу после ввода.

код Проблемы:

String responseMessage = response.getMessage(); 
OutputStreamWriter out = new OutputStreamWriter(httpResponse.getOutputStream()); 
out.write(responseMessage); 
out.close(); 
httpResponse.setContentType("application/json"); 
httpResponse.setContentLength(responseMessage.length()); 
httpResponse.setStatus(response.getResponseCode()); 

Исправлен код:

httpResponse.setStatus(response.getResponseCode()); //Do this first! 
String responseMessage = response.getMessage(); 
OutputStreamWriter out = new OutputStreamWriter(httpResponse.getOutputStream()); 
out.write(responseMessage); 
out.close(); 
httpResponse.setContentType("application/json"); 
httpResponse.setContentLength(responseMessage.length()); 
+0

Да, кто бы это сделал. Рад, что ты понял это! – kentcdodds

+2

Код ответа находится в первой строке ответа HTTP. Если вы пишете достаточно контента для буферов потока, которые нужно очистить, значит, часть ответа будет отправлена ​​обратно клиенту - тогда уже слишком поздно устанавливать код ответа. Очевидно, завиток делал запросы по-другому, чем ваш код, и как-то заставлял буферизацию вести себя по-другому. Не видя ничего другого, я бы предположил, что это может быть связано с Content-Encoding. –

+0

Если код для установки кода состояния работал слишком поздно, то это же относится к настройке полей заголовка. –

1

Пробег: connection.getResponseMessage() Метод? Вероятно, он будет содержать ответ REST, где будет найден фактический код. Ответ на соединение может возникнуть, но фактический ответ операции можно найти в сообщении.

+0

getResponseMessage() возвращает 'OK', что согласуется с getResponseCode() возвращением 200. – Oleksi

+0

Что такое RESTful API вы используете ? – kentcdodds

+0

Это API, который я написал. Ничего публичного. – Oleksi

1

Код, который вы опубликовали, выполняет, как и ожидалось. Вот полный тестовый пример, чтобы доказать это:

import com.sun.net.httpserver.HttpExchange; 
import com.sun.net.httpserver.HttpHandler; 
import com.sun.net.httpserver.HttpServer; 
import org.junit.After; 
import org.junit.Before; 
import org.junit.Test; 

import java.io.IOException; 
import java.io.InputStream; 
import java.net.HttpURLConnection; 
import java.net.InetSocketAddress; 
import java.net.URL; 

import static org.hamcrest.CoreMatchers.equalTo; 
import static org.junit.Assert.assertEquals; 
import static org.junit.Assert.assertThat; 

public class Http206Test { 
    private HttpServer server; 

    @Before 
    public void setUp() throws Exception { 
     server = HttpServer.create(new InetSocketAddress(8080), 0); 
     server.createContext("/", new HttpHandler() { 
      public void handle(HttpExchange t) throws IOException { 
       t.sendResponseHeaders(206, 0); 
       t.getResponseBody().write("I'm a 206 response".getBytes()); 
       t.getResponseBody().close(); 
      } 
     }); 
     server.start(); 
    } 

    @After 
    public void tearDown() throws Exception { 
     server.stop(1); 
    } 

    @Test 
    public void httpUrlConnection206Response() throws Exception { 
     String body = getContent("http://localhost:8080", 206); 
     assertThat(body, equalTo("I'm a 206 response")); 
    } 

    @Test(expected = AssertionError.class) 
    public void httpUrlConnection205Response() throws Exception { 
     getContent("http://localhost:8080", 205); 
    } 

    public String getContent(String url, int expectedResponseCode) throws IOException { 
     URL requestURL = new URL(url); 
     HttpURLConnection connection = (HttpURLConnection) requestURL.openConnection(); 
     try { 
      connection.setRequestProperty("Connection", "close"); 
      connection.setReadTimeout(5000); 
      assertEquals("Request successfully handled", 
        expectedResponseCode, 
        connection.getResponseCode()); 
      InputStream input = connection.getInputStream(); 
      try { 
       return toString(input); 
      } finally { 
       input.close(); 
      } 
     } finally { 
      connection.disconnect(); 
     } 
    } 

    public String toString(InputStream stream) throws IOException { 
     int data; 
     StringBuilder builder = new StringBuilder(); 
     while ((data = stream.read()) != -1) { 
      builder.append((char) data); 
     } 
     return builder.toString(); 
    } 
} 

Это означает, что ваш тест правильный, и есть проблемы с вашим сервисом.

+0

Интересно. Любая идея, почему создание GET с помощью curl для того же URL-адреса возвращает 206? Возможно, я не настраиваю заголовок или что-то еще? – Oleksi

+0

Выяснил это. См. Самостоятельный ответ здесь: http://stackoverflow.com/a/10759669/1165637 – Oleksi

Смежные вопросы