【发布时间】:2015-03-20 12:09:30
【问题描述】:
我正在尝试为单元测试编写一个模拟 HTTP 服务器,为此我使用了 com.sun.net.httpserver 类。 我对 URL 的编码有问题:查询参数是 ISO-8859-1 编码的,但传递给处理程序(通过 HttpExchange)的 URI 不是。 由于我无法更改原始服务器的编码,我想知道是否有办法告诉 HttpServer 在解码 URL 时使用哪种编码。 提前致谢。
这是一个测试程序:
package test34;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main {
public static void main(String[] args) {
try {
MockServer mock = new MockServer();
mock.start(8642);
URL url = new URL("http://localhost:8642/?p="
+ URLEncoder.encode("téléphone", "ISO-8859-1"));
System.out.println(url);
InputStream in = url.openStream();
while (in.read() > 0) {
}
in.close();
mock.stop();
System.out.println(mock.getLastParams().get("p"));
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
这是模拟服务器的代码:
package test34;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class MockServer {
private HttpServer httpServer;
private Map<String, String> params;
public void start(int port) {
if (httpServer == null) {
try {
InetSocketAddress addr = new InetSocketAddress(port);
httpServer = HttpServer.create(addr, 0);
httpServer.createContext("/", new HttpHandler() {
@Override
public void handle(HttpExchange exchange) throws IOException {
try {
handleRoot(exchange);
} catch (RuntimeException e) {
throw e;
} catch (IOException e) {
throw e;
}
}
});
httpServer.setExecutor(Executors.newFixedThreadPool(1));
httpServer.start();
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
}
}
public void stop() {
if (httpServer != null) {
httpServer.stop(10);
httpServer = null;
}
}
public Map<String, String> getLastParams() {
Map<String, String> result = new HashMap<String, String>();
if (params != null) {
result.putAll(params);
}
return result;
}
private void handleRoot(HttpExchange exchange) throws IOException {
URI uri = exchange.getRequestURI();
params = parseQuery(uri.getQuery());
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/plain;charset=ISO-8859-1");
exchange.sendResponseHeaders(200, 0);
OutputStream stream = exchange.getResponseBody();
try {
Writer writer = new OutputStreamWriter(stream, "ISO-8859-1");
try {
PrintWriter out = new PrintWriter(writer);
try {
out.println("OK");
} finally {
out.close();
}
} finally {
writer.close();
}
} finally {
stream.close();
}
}
private static Map<String, String> parseQuery(String qry)
throws IOException {
Map<String, String> result = new HashMap<String, String>();
if (qry != null) {
String defs[] = qry.split("[&]");
for (String def : defs) {
int ix = def.indexOf('=');
if (ix < 0) {
result.put(def, "");
} else {
String name = def.substring(0, ix);
String value = URLDecoder.decode(
def.substring(ix + 1), "ISO-8859-1");
result.put(name, value);
}
}
}
return result;
}
}
【问题讨论】:
-
也许我遗漏了一些东西,但是 HttpExchange.getQueryString() 的 javadoc 说它返回“请求 URI 的未解码查询字符串,如果请求 URI 没有,则返回 null”。如果它没有被解码,并且由于 http 标头必须是 7 位 ASCII (ietf.org/rfc/rfc2616.txt) ,那么您可以稍后使用 URLDecoder.decode(... "ISO-8859-1"); ?
-
我相信你是对的:解码的是 uri.getQuery
-
我应该使用 getRawQuery。请写一个答案,这样我就可以给你功劳了。
-
谢谢,但我想我把它和 javax.xml.ws.spi.http.HttpExchange 混在一起了。 com.sun.net 中没有 HttpExchange.getQueryString 。你可能想编辑我的答案。
标签: java character-encoding httpserver