本来以为浏览器HTTP报文的生成应该是完全一致的。但最近在做一个项目的时候,发现Safari和Chrome提交同一份表单,后端的处理结果不一致。看提交结果呢,是因为Safari多了个回车。由于原项目的提交数据比较复杂,我就写了简单的测试来加以验证。

说是测试,其实也是验证心里的想法:正常的HTTP报文每行结尾符一般用\r\n,那如果我提交的文本里面带了\r\n,那浏览器会不会主动补充成\r\n呢?

从现在的情况来看,Safari是会主动补充成\r\n,而谷歌不会。接下来就来测试一下。

测试前的准备

一、准备一个测试用的Web服务

const Koa = require('koa');
const koaBody = require('koa-body');
const Router = require("koa-router");
const router = new Router();
const app = new Koa(); app.use(koaBody({ multipart: true })); router.get("/browser/returntest", (ctx) => {
ctx.status = 200;
ctx.body = "<form method='post' action='/browser/returntest'><textarea name='str'></textarea><button type='submit'></button></form>";
}); router.post("/browser/returntest", (ctx) => {
console.log(ctx.request.body)
ctx.status = 200;
ctx.body = {
isSuccessful: true,
data: "post,成功",
errCode: 0
};
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(3030);

二、选定测试参数

这次测试主要选定了几个可以上传键值对的Content Type,分别是application/json、application/x-www-form-urlencoded、multipart/form-data。

按理来说:json数据字符串经过转义后\n就是\\n,本来就不是换行,而是反斜杠和字母n;urlencoded会进行url编码,\n就是%0a,也不是换行;而form-data的换行就是换行。

三、选择测试工具

我用的是Charles,用起来比起直接在浏览器看报文更加自由一点。

我平时主要是爬虫需要进行模拟登录时或者爬取手机端时,用它来分析请求报文。

简书上的一篇教程

开始测试

一、编写测试脚本

  1. application/json格式的请求

    var xhr = new XMLHttpRequest;
    xhr.open("post", "/browser/returntest");
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.send(JSON.stringify({
    str: "abc\nabc"
    }));
    // # 等效于
    // curl -H "Content-Type: application/json" -X POST --data '{"str":"abc\nabc"}' http://localhost:3030/browser/returntest
  2. application/x-www-form-urlencoded格式的请求

    var xhr = new XMLHttpRequest;
    xhr.open("post", "/browser/returntest");
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.send("str=abc\nabc");
    // # 等效于
    // curl -H "Content-Type: application/x-www-form-urlencoded" -X POST --data 'str=abc
    // abc' http://localhost:3030/browser/returntest
  3. multipart/form-data格式的请求

    var xhr = new XMLHttpRequest;
    var formData = new FormData
    formData.append("str", "abc\nabc");
    xhr.open("post", "/browser/returntest");
    xhr.send(formData);
    // # 等效于
    // curl -H "Content-Type: multipart/form-data" -X POST --form 'str=abc
    // abc' http://localhost:3030/browser/returntest

二、测试

  1. 启动Nodejs Web服务;
  2. 打开浏览器,输入http://localhost.charlesproxy.com:3030/browser/returntest
  3. 打开Charles;
  4. 打开浏览器控制台,输入脚本进行测试。

三、测试结果

  1. 提交application/json请求(谷歌、Safari结果一致)

    把application/json格式的请求输入到控制台,可以在Charles截获到请求:

    此时nodejs的输出为:

    Charles可以看到请求报文的数据是:

    Charles可以看到请求体的十六进制表示是:

    可以看到,\n就是\n\对应5cn对应6e。(想确认ASCII码的可以看对照表

    application/json测试验证猜想,json数据字符串经过转义后\n就是\\n,本来就不是换行,而是反斜杠和字母n。

  2. 提交application/x-www-form-urlencoded请求(谷歌、Safari结果一致)

    把application/x-www-form-urlencoded格式的请求输入到控制台,可以在Charles截获到请求。

    此时nodejs的输出为:

    Charles可以看到请求报文的数据是:

    Charles可以看到请求体的十六进制表示是:

    这和猜想的倒是有些不一样,xhr.send的时候没有把换行按urlencoded的格式转成%0A,而是以换行的形式传输。更让我意想不到的是,这次Safari也没有在换行前加上回车了,我本来以为Safari补回车或换行是为了严谨性,结果太让人失望了。

  3. 提交application/x-www-form-urlencoded请求的补充测试(谷歌、Safari结果一致)

    xhr.send不行,也许是application/x-www-form-urlencoded格式的数据大多数时候是以表单形式直接提交的吧,那我通过表单直接提交试一下。

    此时在Charles截获到请求:

    请求体的十六进制表示是:

    这次编码了,但是回车(%0D)也给加上了是什么鬼,谷歌也是一样的,这难道是浏览器统一的标准.

    我直接在本地复制一段只有换行的文本呢?好吧,也是一样的。

    综上,通过浏览器表单输入的多行文本多会被补全成\r\n

    nodejs的输出都为:

  4. 提交multipart/form-data请求(谷歌、Safari结果不一致)

    • 谷歌

      把multipart/form-data格式的请求输入到控制台,可以在Charles截获到请求。

      此时nodejs的输出为:

      Charles可以看到请求报文的数据是:

      Charles可以看到请求体的十六进制表示是:

      谷歌测试验证猜想,abc和abc之间只有换行(0a)。

    • Safari

      把multipart/form-data格式的请求输入到控制台,可以在Charles截获到请求。

      此时nodejs的输出为:

      Charles可以看到请求报文的数据是:

      Charles可以看到请求体的十六进制表示是:

      Safari测试验证猜想,abc和abc之间补充上回车(0d)。

      除此之外,我还测试了\r上传会不会补充\n,结果也是会的。

测试小结

实验证明,如果以multipart/form-data数据格式上传带回车或换行的数据,在Safari里会补充成回车换行,而Chrome不会。如果不要回车换行其中的一个,后端还要做校验才是。

这次实验我本来以为Safari补全成回车换行是更严谨的做法,但它这做事做一半就让人很不舒服,要补把application/x-www-form-urlencoded格式的数据也补了嘛。不过从合理性上考虑,毕竟叫urlencoded,我们做数据请求的时候还是要自己做一个编码。

var xhr = new XMLHttpRequest;
xhr.open("post", "/browser/returntest");
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(encodeURI("str=abc\nabc"));
// # 等效于
// curl -H "Content-Type: application/x-www-form-urlencoded" -X POST --data 'str=abc%0aabc' http://localhost:3030/browser/returntest

然后这次测试还不完善,像以multipart/form-data数据格式上传带回车或换行的文件是否会有问题没有测,响应体是否也会被补充成回车换行没有测。有兴趣大家自己测一测吧。

浏览器有别_HTTP报文的回车换行的更多相关文章

  1. 【转载】 C++中回车换行(\n\r)和换行(\r)的区别

    原文:http://blog.csdn.net/xiaofei2010/article/details/8458605 windows下的点一下回车,效果是:回车换行,就是\r\n unix系统下的回 ...

  2. js/jquery 去掉空格.回车.换行

    本文转载自 http://hi.baidu.com/niubore/item/426532faab4ddcc50dd1c8f9 Jquery:$("#accuracy").val( ...

  3. 用UltraEdit软件替换回车换行的窍门

    转载:http://www.zhuantilan.com/jiqiao/46518.html 方法/步骤 1.打开一个原始文档,在文档中各个人物名称是以逗号分隔的,我们下面来尝试把逗号替换为换行符. ...

  4. 【转】去掉Sqlite3 数据库中的前后回车换行符(newline)

    原文: http://www.blogjava.net/pts/archive/2013/06/10/400... 时间: 2013-06-10 转自:http://www.ityuedu.com/a ...

  5. phpcms v9编辑器ckeditor设置回车换行br为段落p标签

    phpcms v9和dedecms自带的编辑器都是使用的ckeditor,在默认情况下使用ckeditor编辑内容时,按下回车键后在源代码显示的是<br>而非<p>标签,对于习 ...

  6. ruby正则匹配回车换行符

    如果你使用/^.*$/这种正则是匹配不到回车换行符的. 所以应该像下面这么写: /^[\s\S]*$/

  7. php去除换行(回车换行)的方法

    php去除换行(回车换行)的三种方法. 代码: <?php     //php 不同系统的换行   //不同系统之间换行的实现是不一样的   //linux 与unix中用 \n   //MAC ...

  8. Oracle的dbms_output包的put()和put_line()的区别只是有没有回车换行吗?(转)

    答案是否 除了自动添加回车换行外,还有就是缓冲区最大容量的问题!! 无论如何设置serveroutput size,10g里 put() 最多只能输出 32767 个byte 而 put_line() ...

  9. shell脚本兼容linux/unix与windows/cygwin的基础(注意处理好CR, LF, CR/LF 回车 换行的问题)

    shell脚本兼容linux/unix与windows/cygwin的基础 :统一文本格式为:unix文本格式,即于LF为换行符(推荐方案) 在notepad上设置:编辑->档案格式转换-> ...

随机推荐

  1. OpenCV 之 透视 n 点问题

    透视 n 点问题,源自相机标定,是计算机视觉的经典问题,广泛应用在机器人定位.SLAM.AR/VR.摄影测量等领域 1  PnP 问题 1.1  定义 已知:相机的内参和畸变系数:世界坐标系中,n 个 ...

  2. epoll经典代码示例

    1. epoll原理 原理性的知识不再另做说明,我在这里附上收藏整理的两篇经典文章: select与epoll的本质关系. select.poll.epoll之间的区别. 2. epoll服务器端经典 ...

  3. RDS导入注意事项

    1)导入文件大小不超过100M,支持格式有CSV.SQL.ZIP 2)sql文件需注释如下内容: SET @@SESSION.SQL_LOG_BIN=0 ; SET @@GLOBAL.GTID_PUR ...

  4. C# windows服务知识集锦

    最近公司项目,本人也是刚接触windows服务,现在把这两天上网学习的一些资料拿出来与大家分享. 1).关于windows服务安装包的制作和自动启动服务 http://blog.csdn.net/re ...

  5. 在 Docker 的 CentOS7 镜像 中安装 mysql

    在 Docker 的 CentOS7 镜像 中安装 mysql 本来以为是个很简单的过程居然折腾了这么久,之前部署云服务器时也没有好好地记录,因此记录下. 特别提醒:本文的操作环境是在 Docker ...

  6. scrum项目冲刺_day02总结

    摘要:今日完成任务. 1.appUI页面完成 2.图像识别正在进行 总任务: 一.appUI页面(已完成) 二.首页功能: 1.图像识别功能 2.语音识别功能 3.垃圾搜索功能 4.相关新闻爬取 三. ...

  7. cnblogs-theme-silence 主题设置简约风格

    本文参考 更改博客皮肤 更改博客皮肤为Custom 页面定制CSS代码 勾选禁用模板默认CSS 导入复制该文件内容到代码框中 配置代码块复制功能 样式 和 右侧滑动条样式 /*复制功能添加按钮 beg ...

  8. PHP中PDO关闭连接的问题

    在之前我们手写 mysql 的连接操作时,一般都会使用 mysql_close() 来进行关闭数据库连接的操作.不过在现代化的开发中,一般使用框架都会让我们忽视了底层的这些封装,而且大部分框架都已经默 ...

  9. ecshop刷新页面出现power by ecshop和链接的解决办法

    当小伙伴在使用echop模板进行修改的时候,如果你删掉底部自带版权后,再调试程序刷新界面的时候,时不时就会冒出一个power by ecshop,而且是带有链接的,很不舒服,所以需要去掉,下面是最简单 ...

  10. Java面向对象系列(12)- Static关键字讲解

    场景一:静态变量 package oop.demo07; public class Student { private static int age;//静态的变量 一般多线程用的比较多 privat ...