我正在设置我自己的java http服务器,以便更好地了解http服务器以及网络内容。我开发了一个非常简单的服务器,并且能够以JSON形式提供html页面和数据。然后我看到了浏览器(我使用的是Chrome,但假设它与其他人一样)正在发送一个favicon.ico请求。我能够在我的服务器上识别出该请求,因此我尝试提供我下载的随机图标并将其调整为png格式的16x16像素,因为互联网所说的大小需要是。这是我的代码,请注意它不应该是专业的,只是适合我的基本教育目的:
[set up ServerSocket and listen]
public static String err_header = "HTTP/1.1 500 ERR\nAccess-Control-Allow-Origin: *";
public static String success_header = "HTTP/1.1 200 OK\nAccess-Control-Allow-Origin: *";
public static String end_header = "\r\n\r\n";
while(true){
try{
System.out.println("Listening for new connections");
clientSocket = server.accept();
System.out.println("Connection established");
InputStreamReader isr = new InputStreamReader(clientSocket.getInputStream());
BufferedReader reader = new BufferedReader(isr);
String getLine = reader.readLine();//first line of HTTP request
handleRequest(getLine,clientSocket);
}//end of try
catch(Exception e){
[error stuff]
}//end of catch
}//end of while
HandleRequest方法:
public static void handleRequest(String getLine,Socket clientSocket) throws Exception{
if(getLine.substring(5,16).equals("favicon.ico")){
List<String> iconTag = new ArrayList<String>();
iconTag.add("\nContent-Type: image/png");
handleFileRequest("[file]",iconTag,clientSocket);
}//end of if
else{
handleFileRequest("[file]",clientSocket);
}//end of else
}//end of handleRequest
图像的handleFileRequest:
public static void handleFileRequest(String fileName,List<String> headerTags,Socket clientSocket) throws Exception{
OutputStream out = clientSocket.getOutputStream();
BufferedReader read = new BufferedReader(new FileReader(fileName));
out.write(success_header.getBytes("UTF-8"));
Iterator<String> itr = headerTags.iterator();
while(itr.hasNext()){
out.write(itr.next().getBytes("UTF-8"));
}//end of while
out.write(end_header.getBytes("UTF-8"));
String readLine = "";
while((readLine = read.readLine())!=null){
out.write(readLine.getBytes("UTF-8"));
}//end of while
out.flush();
out.close();
}//end of handleFileRequest
它似乎工作,因为服务器发送文件,浏览器显示200 OK响应,但没有favicon,当我过滤网络请求只是图像时,页面请求一个图像正在服务但是favicon请求没有在那里列出(favicon请求在&#34;其他&#34;部分)。类似地,当点击另一图像时,图像显示在预览上,而对于favicon请求则不是这种情况。截图:
与此同时,这是另一张图片的样子,它在页面中显示得很好:
我也尝试过包含Content-Length标题,但这似乎没有什么区别。我错过了一些明显的东西吗?
另外,为了澄清,我知道我可以在实际的html页面中包含favicon,目标不是这样做,而是要了解它是如何工作的。
答案 0 :(得分:3)
似乎没有正确提供图标的内容。
我怀疑这很可能是因为您阅读其内容的方式:
while((readLine = read.readLine())!=null){ out.write(readLine.getBytes("UTF-8")); }
逐行阅读二进制内容是不合适的,
因为行的概念,还有UTF-8编码,
在二进制文件的上下文中没有意义。
并且你无法通过这种方式逐行正确读取二进制内容,
因为readLine
的{{1}}方法不会返回整行,因为它会从最后删除换行符。
您无法手动添加换行符,因为您无法确切知道它是什么。
这是一种更简单,更正确的方法来读取二进制文件的内容:
BufferedReader
完成此操作后,可以使用byte[] bytes = Files.readAllBytes(Paths.get("/path/to/file"));
的值轻松生成包含内容长度的正确文件标题。
如果我们澄清一些事情,似乎对你有好处。
在浏览器中打开网址时 浏览器向Web服务器发送GET请求以下载您指定的原始URL的内容。
一旦有了页面内容,它就会发送更多的GET请求:
bytes.length
SERVERNAME/favicon.ico
标记的src
属性中指定的图像<img/>
标记的href
属性中指定的样式表<style/>
代码,依此类推...... favicon纯粹是装饰性的,在浏览器标签标题中显示, 其他资源对于呈现页面至关重要。 它们在像lynx这样的基于文本的浏览器中不是必不可少的, 这样的浏览器显然不会获取这些资源。
这是为什么要求favicon的解释,以及如何。
在最基本的情况下,提供文件有两个重要组成部分:
生成适当的HTTP标头:标头中的每一行都采用<script/>
格式,每行必须以name: value
结尾。
必须至少有一个\n
标题。
标题必须以空行终止。
在终止标题的空行之后,
内容可以是任何东西,甚至二进制。
举例说明,
考虑Content-type
命令,该命令将URL的内容转储到标准输出。
如果您运行curl
,
你会看到html文件的内容。
如果您运行curl url-to-some-html-file
,
你会看到图像文件的内容。
这将是不可读的,你的终端可能会发出有趣的声音。
您可以将输出重定向到curl url-to-some-image-file
的文件,
这会给你一个图像文件,
二进制内容,
您可以在任何图像查看器工具中打开。
简而言之,提供文件实际上只是在curl url-to-some-image-file > image.png
上打印标题,
然后打印一个空行以终止标题,
然后在stdout
上打印内容。
调试正确提供图像的简便方法是使用stdout
将URL保存到文件中,
然后验证保存的文件和原始文件是否相同,
例如,使用curl
命令:
cmp
curl -o file url-to-favicon
cmp file /path/to/original
的输出应为空。
如果在两个文件中发现差异,则此命令仅生成输出。
而不是使用cmp
,
这是实现HTTP服务器的一种非常简单的方法:
ServerSocket