10

我很难弄清楚如何解析非标准的 HTTP 响应。

none 标准响应包含ICY 200 OK代替HTTP 200 OK。这是一个发送非标准 HTTP 响应的示例 URL。
http://50.117.121.162:80

由于 Android 4.4 HttpURLConnection将不再使用这些非标准响应。我曾尝试使用 Apache 的HttpClient,但由于没有标准的 HTTP 响应,它不起作用。然后,我尝试按照添加自定义响应解析器的指南进行操作,但 Android 似乎没有执行此操作所需的所有类。

我真的很难找到解决方案。可能在HttpClient解析非标准响应之前修改它,或者HttpURLConnection可以工作,但我不确定这是否可能......

任何帮助将不胜感激。

4

6 回答 6

3

在对小型/精简版 http 客户端库进行了大量研究之后,我遇到了 apache httpclient for android的这个端口。该库为 http 连接提供了完整的支持。然后我只是简单地修改了源代码,特别是 BasicLineParser 用 HTTP/1.0 替换了 ICY。

于 2013-11-07T12:47:13.867 回答
2

我在使用 KitKat 时遇到了类似的问题,并且成功地使用了在这里找到的两个类用于 http post。它们非常易于使用,您也可以轻松修改协议参数。

于 2013-11-19T15:00:11.123 回答
1

感谢@Michael M,您甚至可以通过继承 BasicLineParser 而不是继承 DefaultResponseParser 来简化它。

我已将代码上传到 gist

要使用它:

IcyGetRequest request = new IcyGetRequest(urlStr);
HttpResponse response = request.get();
int responseCode = response.getStatusLine().getStatusCode();
于 2014-02-06T11:09:12.437 回答
1

在 Android 4.4 中还有另一种解决此问题的方法,但它需要使用 Apache HttpClient。这是基于向 Apache Http 引擎提供自定义响应解析器的可能性,该引擎可以将 ICY 200 OK 更改为 HTTP/1.0 200 OK。这是基于以下中提出的一般思想:

http://hc.apache.org/httpcomponents-client-4.2.x/tutorial/html/advanced.html

我已成功使用以下代码。

public class IcyClientConnection extends DefaultClientConnection{

@Override
protected HttpMessageParser createResponseParser(SessionInputBuffer buffer,
        HttpResponseFactory responseFactory, HttpParams params) {

    return new IcyHttpResponseParser(
            buffer, 
            new BasicLineParser (), 
            responseFactory, 
            params);

}

}


public class IcyClientConnectionOperator extends DefaultClientConnectionOperator {

    public IcyClientConnectionOperator(SchemeRegistry schemes) {
        super(schemes);
    }

    @Override
    public OperatedClientConnection createConnection() {

        return new IcyClientConnection();
    }

}



public class IcyClientConnManager extends SingleClientConnManager  {


    public IcyClientConnManager(HttpParams params, SchemeRegistry schreg) {
        super(params, schreg);
    }

    @Override
    protected ClientConnectionOperator createConnectionOperator(
            SchemeRegistry schreg) {
        return new IcyClientConnectionOperator(schreg);
    }

}

现在您必须扩展默认使用的解析器,并添加将错误的服务器重播更改为更正的代码。通常代码会阻塞在hasProtocolVersion.

public class IcyHttpResponseParser extends DefaultResponseParser{

    private CharArrayBuffer icyLineBuf;

    private int icyMaxGarbageLines = 1000;
    private final HttpResponseFactory icyResponseFactory;




public IcyHttpResponseParser(SessionInputBuffer buffer, LineParser parser,
        HttpResponseFactory responseFactory, HttpParams params) {
    super(buffer, parser, responseFactory, params);

    this.icyLineBuf = new CharArrayBuffer(128);
    icyResponseFactory = responseFactory;
}

@Override
protected HttpMessage parseHead(SessionInputBuffer sessionBuffer)
        throws IOException, HttpException {
    int count = 0;
    ParserCursor cursor = null;
    do {
        // clear the buffer
        this.icyLineBuf.clear();
        final int i = sessionBuffer.readLine(this.icyLineBuf);

        //look for ICY and change to HTTP to provide compatibility with non standard shoutcast servers

        String tmp = icyLineBuf.substring(0, this.icyLineBuf.length());
        if(tmp.contains("ICY ")){
            tmp = tmp.replace("ICY", "HTTP/1.0");
        }
        //copy
        this.icyLineBuf = new CharArrayBuffer(128);
        System.arraycopy(tmp.toCharArray(), 0, icyLineBuf.buffer(), 0, tmp.length());
        icyLineBuf.setLength( tmp.length());


        if (i == -1 && count == 0) {
            // The server just dropped connection on us
            throw new NoHttpResponseException("The target server failed to respond");
        }
        cursor = new ParserCursor(0, this.icyLineBuf.length());
        if (lineParser.hasProtocolVersion(this.icyLineBuf, cursor)) {
            // Got one
            break;
        } else if (i == -1 || count >= this.icyMaxGarbageLines) {
            // Giving up
            throw new ProtocolException("The server failed to respond with a " +
                    "valid HTTP response");
        }
        //if (this.log.isDebugEnabled()) {
        //   this.log.debug("Garbage in response: " + this.lineBuf.toString());
       // }
        count++;
    } while(true);
    //create the status line from the status string
    final StatusLine statusline = lineParser.parseStatusLine(this.icyLineBuf, cursor);
    return this.icyResponseFactory.newHttpResponse(statusline, null);
}
}

插入HttpClient:

Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
Scheme ftp = new Scheme("ftp", PlainSocketFactory.getSocketFactory(), 21);

SchemeRegistry sr = new SchemeRegistry();
sr.register(http);
sr.register(ftp);

HttpClient httpClient = new DefaultHttpClient(new IcyClientConnManager(params, sr), params);

这仍在测试中,但初步结果很有希望。

于 2013-12-13T10:39:27.580 回答
0

Create an runnable that creates socket proxy then you will be able to response with HTTP/1.0 instead of ICY , then just connect to this local socket proxy with your player

于 2013-11-05T19:38:10.277 回答
0

这里是Michal M解决方案的修改,以防您不喜欢创建大量子类只是为了配置已经可用的HttpClient类。

final SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
HttpClient httpClient = new DefaultHttpClient() {
    @Override
    protected ClientConnectionManager createClientConnectionManager() {
        return new SingleClientConnManager(getParams(), schemeRegistry) {
            @Override
            protected ClientConnectionOperator createConnectionOperator(SchemeRegistry schreg) {
                return new DefaultClientConnectionOperator(schreg) {
                    @Override
                    public OperatedClientConnection createConnection() {
                        return new DefaultClientConnection() {
                            @Override
                            protected HttpMessageParser createResponseParser(SessionInputBuffer buffer, HttpResponseFactory responseFactory, HttpParams params) {
                                return new IcyHttpResponseParser(buffer, new BasicLineParser(), responseFactory, params);
                            }
                        };
                    }
                };
            }
        };
    }
};

SchemeRegistry如果一个人可以在DefaultHttpClient课堂上以某种方式掌握的话,可能有一种方法可以让他们过时。

于 2014-02-27T17:15:50.597 回答