美文网首页HTTP网络我爱编程
HTTP Content-Type深入实践

HTTP Content-Type深入实践

作者: 大头8086 | 来源:发表于2017-07-23 20:05 被阅读488次

引子

HTTP是一种网络应用层传输协议,协议就是约定。HTTP头部字段Content-Type约定请求和响应的HTTP body内容编码类型,客户端和服务端根据HTTP头部字段Content-Type正确解码HTTP body内容。
常见的HTTP头部Content-Type:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • application/json
  • application/xml

当然还有更多的类型,比如请求html时是text/html,请求css时是text/css,请求js时是text/javascript...
本文将深入实践Content-Type对HTTP body内容的解码重要性,模拟发送HTTP头部Content-Type:application/json,后端使用Spring boot+Java,前端使用html+javascript+css+jquery。
Content-Type和Content-Length焦不离孟,关于Content-Length可以参考拙作HTTP Content-Length深入实践

HTTP Request Content-Type

前端使用Content-Type:"application/json"编码HTTP请求内容并提交给服务端,服务端使用Content-Type:"application/json"解码HTTP请求内容。下面实践HTTP Request头部Content-Type的作用。
后端Spring boot+Java代码如下,Product类包含三个字段:id,name,price,请自建并引入。

package com.demo.web.http;

import com.demo.domain.http.Product;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("http")
public class ContentTypeController {
    @RequestMapping("/content-type-request")
    public String contentType4Request() {
        return "http/content-type-request";
    }

    @RequestMapping("content-type-request.json")
    @ResponseBody
    public void json4Request(@RequestBody List<Product> products, HttpServletResponse response) throws IOException {
        System.out.println(Arrays.deepToString(products.toArray()));
        response.getWriter().write("Add products success.");
    }
}

前端html+javascript+css+jquery代码如下:

<!DOCTYPE HTML>
<html>
<head>
    <title>HTTP request Content-Type Demo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <script src="http://code.jquery.com/jquery-1.11.3.min.js" type="text/javascript"></script>
</head>
<body>
<button type="button" onclick="addProducts();">向服务器发送json</button>
<p id="msg"></p>
<script>
    var products = new Array();
    products.push({
        id : 1,
        name : "iPhone 6 Plus",
        price : 4987.5
    });
    products.push({
        id : 2,
        name : "iPhone 7 Plus",
        price : 5987.5
    });
    function addProducts() {
        $.ajax({
            type: "POST",
            url: "content-type-request.json",
            data: JSON.stringify(products),
            contentType: "application/json",
            dataType: "text",
            success: function (result) {
                console.log(result);
                $("#msg").html(result);
            },
            error: function () {
                alert("error.");
            }
        });
    }
</script>
</body>
</html>

如图1,点击“向服务器发送json”按钮,ajax请求头部Content-Type:application/json,ajax请求后端方法com.demo.web.http.ContentTypeController#json4Request,后端方法解码HTTP请求内容的products json字段,并打印出来。

图1 HTTP request Content-Type:application/json

当把前端代码的contentType: "application/json",注释,前端页面报如下错误:

图2 HTTP Request头部Content-Type使用默认值
图3 HTTP Request头部Content-Type使用默认值

从图2、图3看,如果不明确指定HTTP Request头部Content-Type,将使用application/x-www-form-urlencoded; charset=UTF-8作为默认值,后端方法com.demo.web.http.ContentTypeController#json4Request不能解码Content-Type:application/x-www-form-urlencoded的HTTP Request body内容,返回HTTP 415错误:不支持的媒体类型(Unsupported media type)。如下后端报错信息也印证这点,说明后端方法com.demo.web.http.ContentTypeController#json4Request只能解码请求头部Content-Type为application/json的HTTP Request body内容。
2017-07-23 17:03:56.917 WARN 24723 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported

HTTP Response Content-Type

服务端使用Content-Type:"application/json"编码HTTP响应body内容返回给前端,前端使用Content-Type:"application/json"解码HTTP响应body内容。下面实践HTTP Response头部Content-Type的作用。

情况1:服务端返回Response Content-Type:application/json,前端dataType不指定值

后端Spring boot+Java代码如下:

package com.demo.web.http;

import com.google.common.collect.Maps;
import com.google.gson.Gson;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

@Controller
@RequestMapping("http")
public class ContentTypeController {
    private final static Gson GSON = new Gson();
    @RequestMapping("/content-type-response")
    public String contentType4Response() {
        return "http/content-type-response";
    }

    @RequestMapping("content-type-response.json")
    @ResponseBody
    public void json4Response(HttpServletResponse response) throws IOException {
        Map<String, Object> map = Maps.newHashMap();
        map.put("name", "datou");
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(GSON.toJson(map));
    }
}

前端html+javascript+css+jquery代码如下:

<!DOCTYPE HTML>
<html>
<head>
    <title>HTTP response Content-Type Demo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <script src="http://code.jquery.com/jquery-1.4.2.min.js" type="text/javascript"></script>
</head>
<body>
<p>Name: <span id="name"></span></p>
<button onclick="show()">show name</button>
<script>
    function show() {
        $.get("content-type-response.json", function (data) {
            console.log(data);
            $("#name").text(data.name);
        });
    }
</script>
</body>
</html>

如图4,点击“show name”按钮,ajax请求后端方法com.demo.web.http.ContentTypeController#json4Response,后端方法返回HTTP响应头部Content-Type:application/json,前端$.get()方法在不指定dataType具体值的情况下解码HTTP响应body内容,data类型是Object,js获取并展示data.name的内容。

图4 服务端返回Response Content-Type:application/json,前端$.get() dataType不指定值
情况2:服务端不返回Response Content-Type:application/json,前端dataType指定值json

后端Spring boot+Java代码注释response.setContentType("application/json;charset=utf-8");
前端html+javascript+css+jquery代码如下,前端dataType指定值"json":

<!DOCTYPE HTML>
<html>
<head>
    <title>HTTP response Content-Type Demo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <script src="http://code.jquery.com/jquery-1.4.2.min.js" type="text/javascript"></script>
</head>
<body>
<p>Name: <span id="name"></span></p>
<button onclick="show()">show name</button>
<script>
    function show() {
        $.get("content-type-response.json", function (data) {
            console.log(data);
            $("#name").text(data.name);
        }, "json");
    }
</script>
</body>
</html>

如图5,点击“show name”按钮,ajax请求后端方法com.demo.web.http.ContentTypeController#json4Response,后端方法返回HTTP响应没有头部字段Content-Type,前端$.get()指定dataType="json"解码HTTP响应body内容,data类型是Object,js获取并展示data.name的内容。

图5 服务端不返回Response Content-Type:application/json,前端dataType指定值"json"
情况3:服务端不返回Response Content-Type:application/json,前端dataType不指定值"json"

后端Spring boot+Java代码注释response.setContentType("application/json;charset=utf-8");
前端html+javascript+css+jquery代码如下,前端$.get()dataType不指定值"json"

<!DOCTYPE HTML>
<html>
<head>
    <title>HTTP response Content-Type Demo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <script src="http://code.jquery.com/jquery-1.4.2.min.js" type="text/javascript"></script>
</head>
<body>
<p>Name: <span id="name"></span></p>
<button onclick="show()">show name</button>
<script>
    function show() {
        $.get("content-type-response.json", function (data) {
            console.log(data);
            $("#name").text(data.name);
        });
    }
</script>
</body>
</html>

如图6,点击“show name”按钮,ajax请求后端方法com.demo.web.http.ContentTypeController#json4Response,后端方法返回HTTP响应不返回头部字段Content-Type,前端$.get()在不指定dataType具体值为"json"的情况下不能解码HTTP响应body的json字符串,data类型是String,js不能获取data.name值,所以展示的Name:为空。

图6 服务端不返回Response Content-Type:application/json,前端dataType不指定值"json"

相关文章

网友评论

    本文标题:HTTP Content-Type深入实践

    本文链接:https://www.haomeiwen.com/subject/ohemkxtx.html

    热点阅读