HTTP学习(4)--违反协议的错误

在这一系列的第二篇博客中,我遇到了一个很严重的问题。当我通过浏览器访问图片的时候,图片可能会无法完全展示出来,尽管多次刷新有可能会完整的显示出来,但是通常还是会只是显示一部分的图片。 我一开始认为这是因为网络的原因,但是本地测试,其实网络的原因基本上可以排除了。我把程序挂在服务器上给别人演示,几乎所有人都无法查看完整的图片,我给的说法也就是你多刷新几次就行了。现在想一想,还是太想当然了。

HTTP学习(3)–解析报文

先来看一看这个错误吧!

错误及其解决方法

错误演示

因为第二篇博客的那个文章的代码有些多余了,所以这里提供一个简化的代码来演示。
注意,我注释的代码部分!

package com.dragon.learn;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.file.Files;

public class Server {
	public static void main(String[] args) throws IOException {
		try (ServerSocket server = new ServerSocket(10000)) {
			while (true) {
				Socket client = server.accept();
				System.out.println("用户连接。。。");
				//这里只写不读。
				OutputStream out = new BufferedOutputStream(client.getOutputStream());
//				InputStream in = new BufferedInputStream(client.getInputStream());
//				StringBuilder request = new StringBuilder(80);
//				while (true) {
//					int c = in.read();
//					if (c == '\r' || c == '\n' || c == -1) break;
//					request.append((char)c);
//				}
				File file = new File("D:/DragonFile/target/attitude.jpg");
				long length = file.length();
				byte[] data = Files.readAllBytes(file.toPath());
			
				String header = "HTTP/1.0 200 OK\r\n" 
						+ "Server: crazy\r\n"
						+ "ContentType-length: " + length + "\r\n"
						+ "Content-Type: " + "image/jpg" + "; charset=" + "UTF-8" + "\r\n\r\n";
				
				out.write(header.getBytes(Charset.forName("UTF-8")));  //响应头
				out.write(data);       //响应体
				out.flush();        //刷新
				client.close();
			}
		}
	}
}

启动服务,使用浏览器访问

浏览器的调试窗口,状态会显示失败,并且下方的数据传输也不对,这种图片大概是1.2M左右。
在这里插入图片描述

刷新
在这里插入图片描述

再刷新
注意,不是越刷新显示越多,它是无规律的,可能多可能少。如果图片比较小的话,可能会显示完全,我现在使用的这张图片大概是1.2MB。所以只能显示一部分,不过这也好,把问题给完全重现出来了。
在这里插入图片描述

一个严重的问题是图片无法下载!
在这里插入图片描述

取消注释代码,再次访问

访问成功,各项数据都是对的。重复访问,结果也是相同的,都是可以正确显示的。

注意:这里我没有做异常处理,所以它是可能发生第二篇博客中的那个错误,从而导致整个程序停止了。不过这个异常是因为客户端的突然关闭,不是编码的问题。
在这里插入图片描述

图片可以正常下载成功
在这里插入图片描述

错误的起因

之所以发生这个错误,是因为我认为我既然消灭了404,那就干脆不读取请求了。因为我不处理请求,所以索性就不去读取请求报文了,只给出响应报文。然后就产生了这个问题,并且我找了两天才发现和是否读取请求报文有关。因为这个在编码上确实是没有问题的,并且还是涉及到了浏览器方面的知识,所以我无法解决。
所以,我就借助了别人的帮助,我在StackOverFlow发了一个问题,几个小时就有人给我了解答。回答,大致说清楚了问题的原因

我在这里贴一下回答的截图:
在这里插入图片描述

翻译:

把Socket想象成两根吸管(一根朝一个方向,另一根朝另一个方向)。如果你把东西放在吸管里,而另一边不把它拿出来,你就会注意到,并且不能再往里面放东西了。HTTP被定义为“客户端将其请求放入,服务器读取请求,然后将响应放入另一根吸管”。你没有从吸管上拿走所有东西,就违反了合同,浏览器不喜欢这样。实际上,浏览器会注意到您的服务器甚至都不接受请求(即使它很短),并且假设非常正确,如果请求甚至都没有被读取,那么响应就不可能是好的。

Because you are violating the protocol.
所以就如这句话所言,我违反了HTTP协议的规定。不读取客户端请求,只是发送响应,看起来是一个很疯狂的事,我居然为了省事就去做了。不过这个知识点是我的盲区了,遇到的时候还是很头疼的。

随带一提

下面这段代码,我是完全读取了请求报文吗?

	InputStream in = new BufferedInputStream(client.getInputStream());
	StringBuilder request = new StringBuilder(80);
	while (true) {
		int c = in.read();
		if (c == '\r' || c == '\n' || c == -1) break;
		request.append((char)c);
	}

如果你看了解析报文那篇博客,应该就会发现我这里只是读取请求报文的第一行。但是按照上面的解释,我应该完全读取整个请求报文才行呀!为什么我只是读取一行就行了呢?
这里涉及到了一个小的知识点:BufferedInputStream 缓冲流的为什么快的特点。缓冲流内部有一个8196大小的字节数组,它会先将数据读取到字节数组中,然后我们对应于流的操作,其实都是在操作内存中的缓冲数组内进行的,所以缓冲流的速度很快。当缓冲数据读取完了,还会再次读取填充到数组中的。 所以,虽然我们只是读取了几个字节的数据,但是缓冲流已经把所有的数据都读入内部的缓冲数组中了。但是只要请求头大于缓冲数组的大小,这样应该也是不行了。只是通常报文是不会有那么大的(除非携带了二进制数据部分)。

如果不使用缓冲流,只是使用如下的代码:

InputStream in = client.getInputStream();

访问结果
虽然有可能访问完整的图片,但是大部分情况下图片还是显示不完全,并且图片是无法下载的,这就说明了问题还是存在的。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

说明

这个问题,表明我们所了解的东西还是太少了。对于这些基础的协议以及浏览器工作的方式,都不太了解。出现了这种底层的问题一般也很难解决,所以必要的时候还是要借助一下社区的力量–站在巨人的肩膀上!

HTTP学习(5)–demo编写(1)

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
股权转让协议书 本协议于 年 月 日由以下各方在深圳市签订: 转让方:     (以下简称“甲方”) 受让方: (以下简称“乙方”) 住所: 法人代表: 鉴于: 第一章、××××有限公司(以下简称“××公司”)系在××工商行政管理局依法注册并有效存续的一家有限责任公司;公司注册资本××万元人民币; 第二章、甲方系“×××”的一个股东,其认购出资额为×××万元人民币,占注册资金总额的66%。 第三章、甲方拟将其持有的×××的66%股权(下称“目标股份”)转让给乙方,乙方同意受让该目标股份。 于此,根据《中华人民共和国公司法》、《中华人民共和国合同法》等有关法律、法规的规定,甲乙双方在平等自愿的基础上通过友好协商,就有关股权转让事宜达成如下协议条款,以资共同遵守。 一、股权转让及转让价款 1.双方商定,甲方转让及乙方受让该目标股份的价格为人民币 万元。 2.自本协议签订生效之日起,乙方按其持有的“××××”的股权比例享受权利和承担义务。 二、股权转让款的支付 乙方应在本协议签署之日起三日内向甲方支付人民币 万元作为定金,余款在工商变更登记手续完成后一次性支付。 三、股权转让手续的办理 1.本协议签署后,甲方应立即通知“××××”,由其将本协议项下的股权转让事项记载于“××××”的股东名册,并督促“航盛领航通”及时到其所属的工商行政管理机关办理相应的股权变更登记手续。 2.上述股权转让变更手续,应当在本协议签署后一个月内完成。股权变更登记手续办理完毕之日视为股权转让正式完成。 四、陈述与保证 为确保本协议的合法有效及顺利履行,甲乙双方在此做出如下陈述与保证。 1.甲方的陈述与保证; 1)保证其为“××××”的合法股东,并对目标股份享有所有权。 2)保证将全面履行本协议,而且已依法取得本协议所必需的,包括“××××”的其他股东在内的任何批准、同意、授权和许可。 3)本协议的签订或履行不违反以甲方为一方或约束甲方自身或其资产的任何重大合同或协议。 4)对其在目标股份拥有完全、有效的处分权,保证目标股份没有设置抵押权、质押权或任何形式的担保,并且上述股权不存在被任何第三人追索的情形,亦不存在被任何司法机关、政府机关和其他任何部门杳封及限制的情形。 5)在本协议中所作的声明和保证均为真实、准确、完整,并在股权过户完成时仍为真实、准确、完整,不存在虚假陈述、重大遗漏和误导之处。 6)保证本协议生效后,不得无故将目标股份再次转让与其他第三人,亦不得将其在本协议项下的权利、义务转让予任何其他第三人。 7)在本协议履行过程中应给予乙方积极的配合,以促使股权转让的过户及其他相关手续顺利完成。 8)除法律、法规另有规定外,保证对于本协议项下股权转让所涉及的一切资料及信息,承担保密义务。 9)甲方需在本协议签订后将与目标股份相关的出资证明文件及其持有的公司公章、银行帐户、财务帐册等资料移交给乙方。 2.乙方的陈述与保证: 1)依照法律设立并有效存续的有限公司。 2)保证自己具有合法的权力签署并全面履行本协议。 3)本协议的签署或履行不违反以乙方为一方或约束乙方自身或其资产的任何重大合同或协议。 4)保证在本协议签署后,不得无故放弃本次股权的受让,亦不得将其在本协议项下的权利、义务转让予任何其他第三人,但股权过户完成后的转让不受此限。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值