zoukankan      html  css  js  c++  java
  • Servlet3.1学习(二)

    Request

    HttpServletRequest代表一个Http请求,你可以从中获取header、cookie、body数据等等。

    获取请求数据

    根据Http协议规范,请求参数分为Query String、Request Body(Form Data、Request Payload)等。其常见请求内容的媒体类型有application/x-www-form-urlencoded、multipart/form-data、text/xml、application/json等等。

    Servlet提供getParameter()、getInputStream()、getPart()等API来获取请求参数数据。

    • GET请求的Query String和POST请求Content-Type为application/x-www-form-urlencoded(Form data)的请求数据由getParameter()类API获取数据且不能使用getInputStream()类API获取数据。个人认为Servlet提供这种简便API获取请求数据,主要是因为这类数据是键值对形式的数据,可以通过key来获取value数据。
    • POST请求Content-Type为multipart/form-data的请求数据(文件上传)通过getPart()类API获取,这是Servlet3.0后启用的API,如果Servlet不支持getPart()类API,同样可以使用getInputStream()获取请求数据。
    • 其他形式的请求数据,例如POST请求JSON数据等,只能通过getInputStream()获取InputStream来自己解码数据。

    GET请求获取请求数据

    GET请求直接通过getParameter()类API获取请求数据,例如如下请求http://localhost/request?key=123

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String value = req.getParameter("key");
        log.info("value: {}", value);
        ResponseUtils.writeJson(resp, ResponseJson.ok());
    }
    

    POST请求获取请求数据

    POST请求的Header有Content-Type字段,其代表该POST的Request Body数据是那种类型的数据。开发者根据不同的Content-Type类型使用不同的API进行获取数据。

    POST Form Data(Content-Type是application/x-www-form-urlencoded)获取请求数据。

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String value = req.getParameter("key");
        log.info("value: {}", value);
        ResponseUtils.writeJson(resp, ResponseJson.ok());
    }
    

    POST Content-Type是其它类型获取请求数据,例如Json数据

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 使用流获取数据
        BufferedInputStream inputStream = new BufferedInputStream(req.getInputStream());
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        int b;
        while ((b = inputStream.read(bytes)) != -1) {
          outputStream.write(bytes, 0, b);
        }
        String result = new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
        User user = JsonUtils.readFromJson(result, User.class);
        CloseUtils.close(inputStream, outputStream);
        ResponseUtils.writeJson(resp, ResponseJson.ok());
    }
    

    文件上传

    文件上传使用POST请求且Content-Type类型为multipart/form-data时,Servlet提供特别的getPart()类API进行获取文件,注意需要为该Servlet配置Multipart-Config信息来进行读取文件。

    @WebServlet(urlPatterns = "/request/post/file")
    @MultipartConfig(location = "E://")
    public class FileReqServlet extends HttpServlet {
    
        private static final long serialVersionUID = 5245909855827709121L;
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            for (Part part : req.getParts()) {
              String fileName = fileNameFromPart(part);
              part.write(fileName);
            }
            ResponseUtils.writeJson(resp, ResponseJson.ok());
        }
    
        /**
         * 从Part中获取文件名称
         *
         * @param part Part
         * @return 文件名称
         */
        private String fileNameFromPart(Part part) {
            String contentDispose = part.getHeader("Content-Disposition");
            // 如果有中文会可能会导致乱码,所以在这里需要编解码
            String decodeStr = new String(contentDispose.getBytes(Charset.forName("GBK")), StandardCharsets.UTF_8);
            // 分割字符串获取文件名
            String[] split = StringUtils.trim(decodeStr).split(";");
            return StringUtils.substringBetween(split[split.length - 1], "="", """);
        }
    }
    

    请求数据解码

    服务器解析Http请求数据时需要解码数据,可能会出现乱码问题,这里讨论一下Http请求数据解码。

    首先看请求数据的编解码:

    graph LR
    浏览器编码-->网络传输
    网络传输-->服务器解码
    

    不同的乱码代表不同的意思:

    • %E4%B8%AD%E5%9B%BD:代表服务器没有解码数据。
    • ??????:代表服务器与浏览器的编解码规范不一致。

    Google Chrome在55版本以后不能手动设置编码格式,在我本地电脑上Google Chrome使用的是UTF-8编码格式进行数据编码,所以我们需要在服务器设置和浏览器一致的编码格式。在Servlet中设计到编码主要在下面两个地方:

    Request URL

    设计到Request URL,Servlet规范中我没有找到其默认的解码格式,在Tomcat 9.0.2中默认是UTF-8编码格式。在Tomcat中可以使用如下配置修改Request URL的解码格式

    <Connector port="8080" protocol="HTTP/1.1"
            connectionTimeout="20000" redirectPort="8443" 
            URIEncoding="GBK"/>
    

    Request Body

    Servlet规格中默认使用"ISO-8859-1"作为解码规范,我们可以使用setCharacterEncoding()API来进行设置解码规范。

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        req.setCharacterEncoding("UTF-8");
        String value = req.getParameter("key");
        log.info("value: {}", value);
        ResponseUtils.writeJson(resp, ResponseJson.ok());
    }
    

    在Tomcat中我们可以使用如下配置修改Request Body编码格式

    <Connector port="8080" protocol="HTTP/1.1"
            connectionTimeout="20000" redirectPort="8443" 
            useBodyEncodingForURI="GBK"/>
    

    我们也可以使用Filter配置所有的请求解码格式。例如:在Spring Boot中会默认注入一个CharacterEncodingFilter进行设置

    public class CharacterEncodingFilter extends OncePerRequestFilter {
    	@Override
    	protected void doFilterInternal(
    		HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
    		throws ServletException, IOException {
    
    		String encoding = getEncoding();
    		if (encoding != null) {
    			if (isForceRequestEncoding() || request.getCharacterEncoding() == null) {
    				request.setCharacterEncoding(encoding);
    			}
    			if (isForceResponseEncoding()) {
    				response.setCharacterEncoding(encoding);
    			}
    		}
    		filterChain.doFilter(request, response);
    	}
    }
    

    Header、Cookie

    HttpServletRequest提供一些API获取Http Header、Cookie

    请求路径

    HttpServletRequest提供一些API获取请求的路径

    • Context Path:主要是Web服务器配置的当前Web应用的Context Path,以"/"开头,或者null
    • Servlet Path:该请求对于的Servlet的映射,以"/"开头
    • PathInfo:请求路径除了Context Path、Servlet Path以外的路径,主要是Servlet模糊匹配。以"/"开头,或者null

    Response

    HttpServletResponse代表一个Http响应,其封装了从服务器返回客户端的所有信息

    编码

    由上面可知,在服务器编码后,浏览器需要解码,这就的保证服务器、浏览器编解码格式必须相同。在我电脑的Google Chrome 63版本中,即使在Content-Type中设置了编码格式,浏览器也不会使用该编码格式,Chrome直接使用了UTF-8的编码格式。

    在HttpServletResponse中通过getWrite()获取PrintWriter进行字符串输出需要进行编码,默认使用ISO-8859-1编码格式,我们可以使用setCharacterEncoding()方法进行修改。

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        resp.setContentType("text/plain");
        resp.setCharacterEncoding("UTF-8");
        System.out.println(resp.getCharacterEncoding());
        PrintWriter writer = resp.getWriter();
        writer.append("中国").flush();
    }
    

    Reference

    http://aub.iteye.com/blog/763117

  • 相关阅读:
    MySQL详细安装(windows)
    深入理解java虚拟机
    java语言实现机制
    java基本类型的长度
    关于SQLite数据库 字段 DateTime 类型
    "初识".Net Winfom
    Linux Shell脚本编程while语句
    mysql主从搭建
    oracle dg状态检查及相关命令
    Oracle 11.2.0.4单实例打补丁
  • 原文地址:https://www.cnblogs.com/maying3010/p/8472079.html
Copyright © 2011-2022 走看看