详解okhttp3 请求头不能为中文的坑

对源码有一定的了解,以为基本可以驾驭了,谁知道,坑来了。

问题描述:

上线接口的某一天,有用户报障,说登录不上,而且陆续有报障。

通过log 发现登录不上,都有一个类似的报错:
“java.lang.IllegalArgumentException: Unexpected char 0x514d at 4 in wifiSsid value: "360免费WiFi-DP" at ”

什么?怎么和wifiSsid有关系了?后来查了一下代码,发现确实在登录接口上通过请求头的形式上传了 wifissid, 也就是连接的wifi的名字。Exception描述是第四个 char ,也就是“免”字?难道是因为中文的原因?当时是这么猜测的。

源码查询

猜测并不能作为判断的标准,然后做了一下测试,果然连接含义中文名字的wifi就有问题,也就是不能添加中文到请求头里面。这是为什么呢?最后还是通过源码进行的求证:

在okhttp的源码Header.java,发现set 和add header, 都会有这个判断:

  private void checkNameAndValue(String name, String value) {
   if (name == null) throw new NullPointerException("name == null");
   if (name.isEmpty()) throw new IllegalArgumentException("name is empty");
   for (int i = 0, length = name.length(); i < length; i++) {
    char c = name.charAt(i);
    if (c <= '\u0020' || c >= '\u007f') {
     throw new IllegalArgumentException(Util.format(
       "Unexpected char %#04x at %d in header name: %s", (int) c, i, name));
    }
   }
   if (value == null) throw new NullPointerException("value == null");
   for (int i = 0, length = value.length(); i < length; i++) {
    char c = value.charAt(i);
    if ((c <= '\u001f' && c != '\t') || c >= '\u007f') {
     throw new IllegalArgumentException(Util.format(
       "Unexpected char %#04x at %d in %s value: %s", (int) c, i, name, value));
    }
   }
  }

嗷,No,果然是这样,踩到深坑了。无论是header的 Key 和Value都是不能含有中文的,一旦判定为有中文的出现,就会抛出异常,中断请求。

后面想了一下,以前使用okhttp2的时候,也有上传相同的请求头,为什么就没有这个问题呢?也同样去查看了一下okhttp2的源码,发现这个判断是okhttp3才有的,okhttp2其实并没有这个判断。

解决方案:

解决方案有以下几种:

  • 不要传了(当然这个不符合需求)
  • 把源码这个地方改了(也不是太好,不知道会不会引起其他问题)
  • 把中文 encode以下(相对较好的办法):
ssid = URLEncoder.encode(ssid);

总结

遇到问题不可怕,主要是要做好分析,及时解决,多做总结,避免后门再次踩同样的坑。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • android Retrofit2+okHttp3使用总结

    使用前准备 Build.gradle文件配置 dependencies配置 compile 'com.squareup.retrofit2:retrofit:2.0.0' compile 'com.squareup.retrofit2:converter-gson:2.0.0' compile 'com.squareup.okhttp3:logging-interceptor:3.2.0' 网络框架搭建 服务创建类封装(HTTP): public class ServiceGenerator {

  • Android中okhttp3.4.1+retrofit2.1.0实现离线缓存

    关于Retrofit+OkHttp的强大这里就不多说了,还没了解的同学可以自行去百度.这篇文章主要讲如何利用Retrofit+OkHttp来实现一个较为简单的缓存策略: 即有网环境下我们请求数据时,如果没有缓存或者缓存过期了,就去服务器拿数据,并且将新缓存保存下来,如果有缓存而且没有过期,则直接使用缓存.无网环境下我们请求数据时,缓存没过期则直接使用缓存,缓存过期了则无法使用,需要重新联网获取服务器数据. 缓存处理还是很有必要的,它有效的减少服务器负荷,降低延迟提升用户体验,同时也方便用户即使在

  • 详解Android中OkHttp3的例子和在子线程更新UI线程的方法

    okHttp用于android的http请求.据说很厉害,我们来一起尝尝鲜.但是使用okHttp也会有一些小坑,后面会讲到如何掉进坑里并爬出来. 首先需要了解一点,这里说的UI线程和主线程是一回事儿.就是唯一可以更新UI的线程.这个只是点会在给okHttp填坑的时候用到.而且,这个内容本身在日常的开发中也经常用到,值得好好学一学. okHttp发起同步请求 第一个列子是一个同步请求的例子. private void performSyncHttpRequest() { OkHttpClient

  • 详解Android使用OKHttp3实现下载(断点续传、显示进度)

    OKHttp3是如今非常流行的Android网络请求框架,那么如何利用Android实现断点续传呢,今天写了个Demo尝试了一下,感觉还是有点意思 准备阶段 我们会用到OKHttp3来做网络请求,使用RxJava来实现线程的切换,并且开启Java8来启用Lambda表达式,毕竟RxJava实现线程切换非常方便,而且数据流的形式也非常舒服,同时Lambda和RxJava配合食用味道更佳 打开我们的app Module下的build.gradle,代码如下 apply plugin: 'com.an

  • Android中Okhttp3实现上传多张图片同时传递参数

    之前上传图片都是直接将图片转化为io流传给服务器,没有用框架传图片. 最近做项目,打算换个方法上传图片. Android发展到现在,Okhttp显得越来越重要,所以,这次我选择用Okhttp上传图片. Okhttp目前已经更新到Okhttp3版本了,用法跟之前相比,也有一些差别.在网上找了很多资料, 并和java后台同事反复调试,终于成功上传多张图片,同时传递一些键值对参数. 以下是我对该过程的封装: private static final MediaType MEDIA_TYPE_PNG =

  • Android中okhttp3使用详解

    一.引入包 在项目module下的build.gradle添加okhttp3依赖 compile 'com.squareup.okhttp3:okhttp:3.3.1' 二.基本使用 1.okhttp3 Get 方法 1.1 .okhttp3 同步 Get方法 /** * 同步Get方法 */ private void okHttp_synchronousGet() { new Thread(new Runnable() { @Override public void run() { try {

  • 详解okhttp3 请求头不能为中文的坑

    对源码有一定的了解,以为基本可以驾驭了,谁知道,坑来了. 问题描述: 上线接口的某一天,有用户报障,说登录不上,而且陆续有报障. 通过log 发现登录不上,都有一个类似的报错: "java.lang.IllegalArgumentException: Unexpected char 0x514d at 4 in wifiSsid value: "360免费WiFi-DP" at " 什么?怎么和wifiSsid有关系了?后来查了一下代码,发现确实在登录接口上通过请求

  • 详解Http请求中Content-Type讲解以及在Spring MVC中的应用

    详解Http请求中Content-Type讲解以及在Spring MVC中的应用 引言: 在Http请求中,我们每天都在使用Content-type来指定不同格式的请求信息,但是却很少有人去全面了解content-type中允许的值有多少,这里将讲解Content-Type的可用值,以及在spring MVC中如何使用它们来映射请求信息. 1.  Content-Type MediaType,即是Internet Media Type,互联网媒体类型:也叫做MIME类型,在Http协议消息头中,

  • 详解HTTP请求与响应基础及实例

    详解HTTP请求与响应基础及实例 一.HTTP的请求与响应 二.HttpServletRequest和HttpServletResponse对象获取HTTP响应和请求 一.HTTP的请求与响应 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议.是客户端和服务器端之间数据传输的格式规范. 通常,由HTTP客户端发起一个请求,服务端一旦收到请求,向客户端返回一个相应(一个请求的发出,有且只有一个响应). (一)

  • 详解nginx请求头数据读取流程

    在上一篇文章中,我们讲解了nginx是如何读取请求行的数据,并且解析请求行的.本文我们则主要讲解nginx是如何读取客户端发送来的请求头的数据,并且解析这些数据的.本质上来讲,请求行的数据和请求头的数据读取流程是基本一致的,因为其都面临着如何从间断的数据流中读取到数据,也面临着如何对数据进行处理的问题. 1. 请求头读取主流程 在介绍请求头的读取流程之前,我们首先展示一个http请求报文的示例: POST /web/book/read HTTP/1.1 Host: localhost Conne

  • 详解http请求中的Content-Type

    详解http请求中的Content-Type 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 示例说明 * 前端使用Content-

  • 实例详解JSON取值(key是中文或者数字)方式

    JSON取值(key是中文或者数字)方式详解 先准备一个json对象用于演示 var json = {'name':'zhangsan', '年龄':23, 404:'你可能迷路了'}; 1.使用JS中with关键字 with(json) { console.log(name);//输出:zhangsan console.log(年龄);//输出:23 console.log(404);//输出:404,用这种方法读取key是数字的属性,有问题 } 2.最常见的传统的读取key console.

  • 详解PHP用mb_string处理windows中文字符

    我们都知道windows中(当然是中文版),文件名和文件内容等编码都是gbk,而我们在开发过程中,IDE里的编码则是UTF-8,(这里不讨论为什么等等问题,只考虑怎么把编码转变成一样的)所以导致我写的UTF-8编码的正则模式字符串中的中文在gbk编码的文件中并不能正确匹配. 一开始,我并没有什么办法,试过把PHP脚本文件的编码也改成GBK,也可以用,但是想到这种方法太low了,所以找一找PHP中有没有函数可以满足我的需求. 这时,我想到了以前在处理windows中的文件名时用的函数iconv()

  • Spring Boot详解各类请求和响应的处理方法

    目录 1. HttpServletRequest与HttpServletResponse 2. GET类型的请求 2.1 /students?current=1&limit=20 2.2 /student/123 3. POST类型的请求 4. 响应HTML格式的数据 4.1 使用ModelAndView 4.2 使用Model 5. 响应JSON格式的数据 5.1 单组数据 5.2 多组数据 1. HttpServletRequest与HttpServletResponse 浏览器输入:htt

  • 详解C++ 运算符重载中返回值的坑

    相信不少朋友在学习运算符重载的时候,都会被参数与返回值应该是左值引用,还是右值引用,还是const常量所困扰.当然我无法一一枚举,这次先讲一下返回值的坑 (没错就是我亲手写的bug) E0334 "Myclass" 没有适当的复制构造函数 其实这个问题的根源是,没有定义常量参数类型的拷贝构造函数所致 先来看看代码 //头文件head.h class Myclass { private: int a; public: Myclass(int b=0):a(b) {} //构造函数 Myc

  • 详解mybatis-plus的 mapper.xml 路径配置的坑

    mybatis-plus今天遇到一个问题,就是mybatis 没有读取到mapper.xml 文件. 特此记录一下,问题如下: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.husy.mapper.SystemUserMapper.findUserByName at com.baomidou.mybatisplus.core.override.MybatisMapperMe

随机推荐