java笔记2-servlet-处理请求与响应

目标

  • 怎么处理请求与响应
    • web容器到底是怎么实现请求与响应的
    • HttpServletRequest处理请求
      • http请求头信息有哪些
      • get/post获取参数
      • get/post编码
      • 上传图片怎么解决?(http协议body数据怎么获取?)
      • 容器内部如何共享数据?
      • 两个servlet程序之间如何调用?
      • 内部转发到底是什么逻辑?
    • HttpServletResponse处理响应
      • http响应头信息有哪些
      • 输出内容也是需要编码的!
      • 二进制响应
      • 重定向
      • 直接输出错误状态(404)

1. web容器到底是怎么实现请求与响应的?

Paste_Image.png
  1. web容器接收到HTTP服务器转发的请求内容
  2. 初始化HttpServletRequest对象,然后用相关参数进行赋值
  3. 初始化HttpServletResponse对象
  4. 初始化HttpServlet的实现类,调用它的service函数,并把HttpServletRequest和HttpServletResponse两个对象传递过去
  5. service调用doXXX函数,在该函数中,使用request的getParamter()函数获取参数
  6. 处理相应的业务逻辑
  7. 设置response的setContentType输出文件类型和编码
  8. 调用HttpServletResponse的getWriter()函数获得输出用的PrintWriter对象,然后通过函数println()打印输出html

需注意的是:

  1. 一次请求和响应是一个生命周期,在该周期呢,HttpServletRequest和HttpServletResponse由容器负责创建和销毁,它们不能跨越生命周期
  2. web容器在一个生命周期内处理的流程已经很清晰了,试想,如果没有web容器,这些工作都要由程序员每次编码实现,很复杂!因此容器将系统自身业务逻辑和软件需求业务逻辑进行分离,开发人员只需要编写软件需求业务逻辑即可!

servlet原来设计是处理各种网络协议的,因此提供的请求和响应对象类型是ServletRequest和ServletResponse,HttpServlet将这两个对象转化为HttpServletRequest和HttpServletResponse,请看具体代码:

Paste_Image.png

然后在service里面调用实际的doXXX相关函数:

Paste_Image.png

2. HttpServletRequest处理请求

  • http请求头信息有哪些?

标示字段 含义
Accept 客户端支持的数据类型
Accept-Charset 客户端支持的编码
Acctpt-Encoding 客户端支持哪种数据压缩格式
Acctpt-Language 客户端采用的是那种开发语言
Host 客户端想访问的服务器主机
if-Modified-Since 数据在客户端缓存的时间
Referer 客户端从哪个页面来的
User-Agent 客户端的操作系统和浏览器信息
Cookie cookie数据
Connection 持否需要持久链接
Content_length 表示请求消息正文的长度

这是ljlj的请求头信息截图:

Paste_Image.png
  • GET/POST获取参数及标头

取得web应用程序环境路径:getContextPath()

获取参数

函数 功能描述
getParameter(参数名称) 获取指定参数名称的值
getParameterValues() 同一个请求参数会有多个值,返回的是一个数组,返回类型为Enumeration对象
getParameterNames() 返回所有参数的名称
getParameterMap 以key/value的方式返回参数与值

获取标头

函数 功能描述
getHeader(参数名称) 获取指定参数名称的标头
getHeaders() 类似于getParameterValues函数,返回的也是Enumeration对象
getHeaderNames() 返回所有标头参数名称
  • GET/POST编码

编码问题主要是针对非ASCII码字符

-------------------------------post请求-------------------------------

浏览器端
Content-Type标头中会设置字符编码

Context-Type:text/html;charset=UTF-8

相当于是做了如下操作:

String text = java.net.URLEncoding.encode("林","UTF-8")

容器端
容器端默认的编码是:ISO-8859-1,所以如果要取得正确的中文字符,就需要:

req.setCharacterEncoding("UTF-8");
-------------------------------get请求-------------------------------

get请求的浏览器端和post一样,不再赘述!

HTTP服务器端
这里为什么和post不一样,post是容器端,而这里是HTTP服务器端?
因为处理URL的是http服务器,而不是web容器,因此get参数不能使用HttpServletRequest对象!!
get获取参数只能是获得参数后,在进行编码转换,它会使用到String对象的getBytes()函数,具体方式如下:

String name = req.getParameter("name");
String name = new String(name.getBytes("ISO-8859-1","UTF-8"));
  • 上传图片怎么解决?(http协议body数据怎么获取?)

先来确认一下http协议body数据是什么?http协议一般是由请求行、请求头部、空行和请求数据四部分组成的:

Paste_Image.png

GET请求没有body

GET /hello/index.html HTTP/1.1 
#【↑】request line
#【↓】request headers
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
Host: localhost:8000
#发送完关闭连接 or 等待
Connection: Keep-Alive
Cookie: JSESSIONID=BBBA54D519F7A320A54211F0107F5EA6

post请求的表单数据就是body

#url的部分仍然是urlencoded
POST /hello/checkUser.html?opt=xxx HTTP/1.1
Referer: http://localhost:8000/hello/index.html
Accept: */*
Accept-Language: zh-cn
#纯文本的编码:不编码
Content-Type: text/plain
Accept-Encoding: gzip, deflate
Host: localhost:8000
Content-Length: 20
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=BBBA54D519F7A320A54211F0107F5EA6

#【↑】/r/n
#【↓】request body
hl=zh-CN&source=hp&q=domety  

搞清楚body的原理后,把取body数据分为两种,一种是简单的字符串表单,里面的都是文字,另一种就是文件上传了。

---------字符串------------
HttpServletRequest定义了getReader()方法,可以获得BufferReadere对象,通过该对象,就可以访问body中的数据

Paste_Image.png

---------文件(图片)上传------------
有两种方式,一种是用HttpServletRequest的getInputStream()函数获取ServletInputStream对象,是一种串流对象,来处理上传文件。另一种就是servlet3.0中使用的Part进行操作。前一种有点落伍,就不赘述了!

使用Part处理上传图片,必须加上@WebServlet("/upload.do")

Paste_Image.png
  • 容器内部如何共享数据?

req.setAttrbute()
req.getAttrbute()
req.getAttrbuteNames()
req.removeAttrbute()

在一个请求的生命周期内,php共享数据靠session,java可以设置HttpServletRequest的属性,来在整个生命周期内,不论转发了多少个servlet,这些属性都存在。
有些保留的属性名称就不要设置了:

Paste_Image.png
  • 两个servlet程序之间如何调用?

request.getRequestDispatcher("some.do").include(request,response)
request.getRequestDispatcher("some.do?data=xxx").include(request,response)
  • 内部转发到底是什么逻辑?

在调用forward函数前,当前servlet不能对请求进行响应(例如打印字符串),如果有响应但未确认(缓冲区未满或未调用任何清除方法),则响应设置会被忽略。如果有效应且已确认,然后在调用forward()方法,则会抛出IllegalStateException异常

request.getRequestDispatcher("some.do").forward(request.response);

3. HttpServletResponse处理响应

  • http响应头信息有哪些?

头标示 头标示解释
Location 表示客户端应该到哪里去提取文档
Content-Encoding 文档的编码方式
Content-Length 表示内容长度
Content-Type 表示后面的文档属于哪种MIME类型
Last-Modified 文档的最后修改时间
Expires 文档什么时候过期
Refresh 表示浏览器因该在多少时间之后刷新文档
Server 服务器名字
Set-Cookie 设置和页面关联的cookie
Paste_Image.png

---------------常规的设置标头的函数---------------

  • setHeader() 设置标头名称和值
  • addHeader() 给同一标头名称上附加值
  • setIntHeader() 如果标头的值是整数
  • addIntHeader() 同理
  • setDateHeader() 如果标头的值是日期时间
  • addDateHeader() 同理

所有的标头设置必须在响应输出确认之前,如果在之后,所有的设置会被忽略

---------------响应输出有缓冲区---------------
只有在缓冲区满或者强制刷新缓冲区的情况下,才会真正的输出内容到客户端浏览器。

  • getBufferSize()
  • setBufferSize()
  • isCommited() 查看缓冲区的内容是否已经确认
  • reset()
  • resetBuffer()
  • flushBuffer()

在调用HttpServletResponse的getWrite()或getOutputStream()方法之后调用setBufferSize(),会抛出IllegalStateException。(也就是在调用输出函数之前就得设置好缓冲区)
在响应输出确认之后,调用reset(),resetBuffer()会抛出IllegalStateException异常。(确认的输出不能随意重置)

  • 输出内容也是需要编码的!

HttpServletResponse对象的setCharacterEncoding()和setContextType()都能设置编码,建议使用后者,连同文件内容类型一起设置

response.setContextType("text/html","UTF-8")
  • 二进制响应

在大部分情况下,会从HttpServletResponse取得PrintWriter实例,使用println()对浏览器进行字符输出。但是有时候,需要直接对浏览器进行字节输出,这时候可以使用HttpServletResponse的getOutputStream()方法取得ServletOutputStream实例,他是OutputStream的子类。

区分字符流输出和字节流输出,前者主要用来处理文字,包括多国语言的识别。而字节流主要用来处理文字意外的数据,例如二进制文件,图片,PDF文件

Paste_Image.png

这段代码就展示了如果向浏览器输出一个PDF文件,如果浏览器有第三方插件可以在线打开这个字节流pdf文件,那就直接显示,否则提示下载。

  • 重定向

Paste_Image.png
response.sendRedirect("http://xxxxxx.com");

重定向其实也是利用了HTTP状态吗和标头,因此重定向前,不能有响应输出确认,否则会抛出异常

  • 直接输出错误状态(404)

    response.sendError(HttpServletResponse.SC_NOT_FOUND)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 0 系列目录# WEB请求处理 WEB请求处理一:浏览器请求发起处理 WEB请求处理二:Nginx请求反向代理 本...
    七寸知架构阅读 13,876评论 22 190
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,567评论 18 399
  • 目标 servlet的生命周期 servletConfig与ServletContext定义,及其二者的区别 监听...
    arkulo阅读 939评论 0 5
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,174评论 11 349