论坛首页 入门技术论坛

如何确定HTTP请求报头的字符编码?

浏览 6504 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-04-14  
需求及问题:我想实现一个能分块下载文件的模块(这儿只考虑HTTP协议的URL),现在已知的是一个文件的下载URL,比如
引用
http://202.113.18.30:8003/mp3/流行歌曲/beyond/请将手放开/请将手放开.mp3

   为了能够实现分块下载,我要先得到文件的相关信息,比如文件的大小,以及这个URL的服务器支持的HTTP协议的版本。
    因此我先向服务器发送一个HEAD请求,其请求行应该是这样:
引用

HEAD /mp3/流行歌曲/beyond/请将手放开/请将手放开.mp3 HTTP/1.1

    现在的问题是,Request-URI(/mp3/流行歌曲/beyond/请将手放开/请将手放开.mp3 )中含有中文字符,因此发送的时候需要用适当的字符编码将它编码为字节流。那么我怎样才能得到这个字符编码的信息呢?
   发表时间:2007-04-14  
附:我现在的实现代码
private static DataInfo getDataInfo(URL addr)throws IOException{
        String host =addr.getHost();
        String file =addr.getFile();
        int port =addr.getPort();
        if(port==-1) port =80;
        Socket s =new Socket(host,port);
        PrintStream out =new PrintStream(s.getOutputStream(),false,"gb2312");
        BufferedReader in =new BufferedReader(
                               new InputStreamReader(s.getInputStream(),"gb2312"));
        out.print("HEAD "+file+" HTTP/1.1\r\n");
        out.print("Host: "+host+":"+port+"\r\n");
        out.print("Accept: */*\r\n");
        out.print("Referer: "+addr+"\r\n"); 
        out.print("User-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)\r\n");
        out.print("\r\n");
        out.flush();
        String str;
        while((str=in.readLine())!=null){ 
            //解析信息
        }
        out.close();
        in.close();
        ...
    }
0 请登录后投票
   发表时间:2007-04-14  
http header一般都是iso8859-1的,除非给服务器配置时做特殊的设定
0 请登录后投票
   发表时间:2007-04-15  
试试这个:
out.print("HEAD "+URLEncode.encode(file)+" HTTP/1.1\r\n"); 
0 请登录后投票
   发表时间:2007-04-16  
谢谢楼上两位的回答~

out.print("HEAD "+URLEncode.encode(file)+" HTTP/1.1\r\n"); 

这种方法事实上用了平台默认的编码(在我的电脑上是GBK)来进行URL编码
0 请登录后投票
   发表时间:2007-04-16  
Eastsun 写道
谢谢楼上两位的回答~

out.print("HEAD "+URLEncode.encode(file)+" HTTP/1.1\r\n"); 

这种方法事实上用了平台默认的编码(在我的电脑上是GBK)来进行URL编码


那你试试这个?

public static String encode(String s,String enc) throws UnsupportedEncodingException
0 请登录后投票
   发表时间:2007-04-16  
我现在的问题关键是怎么确定这个字符编码enc


注意我想知道的是请求报头的编码,而不是传输内容的字符编码~
0 请登录后投票
   发表时间:2007-04-16  
经过我初步对JDK中源代码的研究,这个编码貌似是由
   System.getProperty("file.encoding", "ISO8859_1");

确定的。


我查找的路线:
java.net.URL中的HTTP协议是由sun.net.www.protocol.http.Handler实现的:
package sun.net.www.protocol.http;

import java.io.IOException;
import java.net.URL;
import java.net.Proxy;

/** open an http input stream given a URL */
public class Handler extends java.net.URLStreamHandler {
    protected String proxy;
    protected int proxyPort;

    protected int getDefaultPort() {
        return 80;
    }

    public Handler () {
	proxy = null;
	proxyPort = -1;
    }

    public Handler (String proxy, int port) {
	this.proxy = proxy;
	this.proxyPort = port;
    }

    protected java.net.URLConnection openConnection(URL u)
    throws IOException {
	return openConnection(u, (Proxy)null);
    }

    protected java.net.URLConnection openConnection(URL u, Proxy p)
	throws IOException {
	return new HttpURLConnection(u, p, this);
    }
}


而这个sun.net.www.protocol.http.HttpURLConnection有代码:
private void writeRequests() throws IOException {
        ...
        http.writeRequests(requests, poster);
        ...
}


其中的http是个sun.net.www.http.HttpClient类:
//HttpClient的writeRequests方法
public void writeRequests(MessageHeader head, 
			      PosterOutputStream pos) throws IOException {
	requests = head;
	requests.print(serverOutput);
	poster = pos;
	if (poster != null)
	    poster.writeTo(serverOutput);
	serverOutput.flush();
    }


其中requests.print方法的代码是:
public synchronized void print(PrintStream p) {
	for (int i = 0; i < nkeys; i++) 
	    if (keys[i] != null) {
		p.print(keys[i] + 
		    (values[i] != null ? ": "+values[i]: "") + "\r\n");
	    }
	p.print("\r\n");
	p.flush();
    }


serverOutput的代码是:
public void openServer(String server, int port) throws IOException {
	serverSocket = doConnect(server, port);
	try {
 	    serverOutput = new PrintStream(
 	        new BufferedOutputStream(serverSocket.getOutputStream()), 
 					 false, encoding);
 	} catch (UnsupportedEncodingException e) {
 	    throw new InternalError(encoding+" encoding not found");
 	}
	serverSocket.setTcpNoDelay(true);
    }



而其中encoding是由HttpClient的父类NetworkClient决定的:
protected static String encoding;

    static {
	final int vals[] = {0, 0};
	final String encs[] = { null };

	AccessController.doPrivileged(
		new PrivilegedAction() {
		    public Object run() {
			vals[0] = Integer.getInteger("sun.net.client.defaultReadTimeout", 0).intValue();
			vals[1] = Integer.getInteger("sun.net.client.defaultConnectTimeout", 0).intValue();
			encs[0] = System.getProperty("file.encoding", "ISO8859_1");
			return null;
	    }
	});
	if (vals[0] == 0)
	    defaultSoTimeout = -1;
	else 
	    defaultSoTimeout = vals[0];

        if (vals[1] == 0)
            defaultConnectTimeout = -1;
        else
            defaultConnectTimeout = vals[1];


	[color=red]encoding = encs[0];[/color]
	try {
    	    if (!isASCIISuperset (encoding)) {
	    	encoding = "ISO8859_1";
    	    }
	} catch (Exception e) {
	    encoding = "ISO8859_1";
    	}
    }
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics