• application/json 与 application/x-www-form-urlencoded的简单比较


    在用HttpUrlConnection请求极光推送restful时(http://docs.jiguang.cn/jpush/server/old/rest_api_v2_push/),

    涉及到一个参数序列化问题,对方要求

    HTTP Post 的Content-Type 需采用 application/x-www-form-urlencoded

    然后序列化时用了json(Map.tostring)导致对方的服务器没有接收到参数,于是改成 后者,

    代码参数做了调整

        private static String json2String(JSONObject json) throws UnsupportedEncodingException {
            Iterator<String> sIterator = json.keys();
            String urlpara = "";
            while (sIterator.hasNext()) {
                String key = sIterator.next();
                //根据键获得值,值也可以是JSONObject,JSONArray,使用对应的参数接收即可
                String value = json.getString(key);
    
                urlpara += key + "=" + URLEncoder.encode(value, "UTF-8") + "&";
            }
    
            return  urlpara;
        }


    done

    (一)

    参考:http://blog.csdn.net/mygoon/article/details/48546781

    package wzq.j2se;

    import java.io.BufferedReader;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.net.URLEncoder;

    public class HttpURLConnectionPost {

     /**
      * @param args
      * @throws IOException 
      */
     public static void main(String[] args) throws IOException {
      readContentFromPost();
     }
     public static void readContentFromPost() throws IOException {
            // Post请求的url,与get不同的是不需要带参数
            URL postUrl = new URL("http://www.wangzhiqiang87.cn");
            // 打开连接
            HttpURLConnection connection = (HttpURLConnection) postUrl.openConnection();
          
            // 设置是否向connection输出,因为这个是post请求,参数要放在
            // http正文内,因此需要设为true
            connection.setDoOutput(true);
            // Read from the connection. Default is true.
            connection.setDoInput(true);
            // 默认是 GET方式
            connection.setRequestMethod("POST");
           
            // Post 请求不能使用缓存
            connection.setUseCaches(false);
           
            connection.setInstanceFollowRedirects(true);
           
            // 配置本次连接的Content-type,配置为application/x-www-form-urlencoded的
            // 意思是正文是urlencoded编码过的form参数,下面我们可以看到我们对正文内容使用URLEncoder.encode
            // 进行编码
            connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
            // 连接,从postUrl.openConnection()至此的配置必须要在connect之前完成,
            // 要注意的是connection.getOutputStream会隐含的进行connect。
            connection.connect();
            DataOutputStream out = new DataOutputStream(connection
                    .getOutputStream());
            // The URL-encoded contend
            // 正文,正文内容其实跟get的URL中 '? '后的参数字符串一致
            String content = "account=" + URLEncoder.encode("一个大肥人", "UTF-8");
            content +="&pswd="+URLEncoder.encode("两个个大肥人", "UTF-8");;
            // DataOutputStream.writeBytes将字符串中的16位的unicode字符以8位的字符形式写到流里面
            out.writeBytes(content);

            out.flush();
            out.close(); 
            
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            
            while ((line = reader.readLine()) != null){
                System.out.println(line);
            }
          
            reader.close();
            connection.disconnect();
    }

    }

    在接收端,这样获取参数:
    String name = request.getParameter("account");
    String pswd = request.getParameter("pswd");
     
     System.out.println(new String(name.getBytes("iso-8859-1"),"UTF-8")); 
     System.out.println(new String(pswd.getBytes("iso-8859-1"),"UTF-8"));

    (二)

    https://segmentfault.com/a/1190000007252829

    application/x-www-form-urlencoded

    提交请求示例

    curl -X POST 'http://localhost:8080/formPost' -d 'id=1&name=foo&mobile=13612345678'

    wireshark抓包结果

    对应的服务端解析参数源码

    //org.springframework.web.method.annotation.RequestParamMethodArgumentResolver#resolveName
    if (arg == null) {
       String[] paramValues = webRequest.getParameterValues(name);
       if (paramValues != null) {
          arg = paramValues.length == 1 ? paramValues[0] : paramValues;
       }
    }

    application/json

    提交请求示例

    curl -X POST -H "Content-Type: application/json" 'http://localhost:8080/jsonPost' -d '{"id":2,"name":"foo","mobile":"13656635451"}'

    wireshark抓包结果

    对应的服务端解析参数源码

    //com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter#readInternal
    protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        InputStream in = inputMessage.getBody();
        byte[] buf = new byte[1024];
    
        while(true) {
            int bytes = in.read(buf);
            if(bytes == -1) {
                byte[] bytes1 = baos.toByteArray();
                return JSON.parseObject(bytes1, 0, bytes1.length, this.charset.newDecoder(), clazz, new Feature[0]);
            }
    
            if(bytes > 0) {
                baos.write(buf, 0, bytes);
            }
        }
    }

    混用示例

    web层代码

        @RequestMapping(value="/mixPost", method=RequestMethod.POST )
        public Result<Void> mixPostTest(@RequestBody @Valid Foo foo, @RequestParam Integer sex)

    提交请求

    curl -X POST -H "Content-Type: application/json" 'http://localhost:8080/mixPost?sex=1' -d '{"id":2,"name":"foo","mobile":"13656635451"}'

    补充--如何定位对应的源码

    找到post请求解析参数源码

        @RequestMapping(value="/formPost", method=RequestMethod.POST )
        public Result<Void> formPostTest(@RequestParam int id, @RequestParam String name, @RequestParam String mobile)

    因为id是必填参数 如果请求参数中不含id的话 会报错 如下所示

    org.springframework.web.bind.MissingServletRequestParameterException: Required int parameter 'id' is not present
        at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:255)
        at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:95)
        at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:79)
        at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:157)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:124)

    通过此方法可以快速定位到源码

    找到json请求解析参数的源码

        @RequestMapping(value="/jsonPost", method=RequestMethod.POST )
        public Result<Void> jsonPostTest(@RequestBody @Valid Foo foo)

    因为肯定要先构造一个空Foo对象 然后才能注入各属性值 所以在Foo的无参构造函数中加断点, 可以定位到json请求解析参数的源码


  • 相关阅读:
    firefox打开链接自动跳转至新页面设置
    sql server 查询不为空的字段
    C# 判断ip地址是否正确
    Win7自带功能,刻录光盘遇到的问题
    【一起学源码-微服务】Nexflix Eureka 源码六:在眼花缭乱的代码中,EurekaClient是如何注册的?
    【一起学源码-微服务】Nexflix Eureka 源码五:EurekaClient启动要经历哪些艰难险阻?
    【一起学源码-微服务】Nexflix Eureka 源码四:EurekaServer启动之完成上下文构建及EurekaServer总结
    【一起学源码-微服务】Nexflix Eureka 源码三:EurekaServer启动之EurekaServer上下文EurekaClient创建
    【一起学源码-微服务】Nexflix Eureka 源码二:EurekaServer启动之配置文件加载以及面向接口的配置项读取
    【一起学源码-微服务】Netflix Eureka 源码一:Netflix Eureka 源码初探,我们为什么要读源码?
  • 原文地址:https://www.cnblogs.com/silyvin/p/9106771.html
Copyright © 2020-2023  润新知