由 POST 400 错误拔出来的萝卜

缘起

  前段时间遇到扫描问题,好不容易拿到了扫描出来的数据,结果调用接口时弹了个 400(Bad request) 给我,匆匆找了点资料修补上线后,忐忑的心也可以安分点。然后,顺着这个 400 的萝卜,拔出了一大堆的坑。

400 (Bad request)

  400 错误的原因很简单,请求头部信息与请求体中的数据格式不匹配,或者 前 -> 后 的数据中字段类型不一致。在有效沟通的前提下,类型不一致的概率很小,那么这个问题就主要集中在头部信息与请求体数据格式不一致上面了。

  先看一个正确的请求:

$.ajax({
    url : "http://localhost:8080/xxx/xxxx",
    type : "POST",
    contentType: "application/json;charset=utf-8",
    data : JSON.stringify({ name, passwd }), //  { name, passwd } es6 的一个语法
    success : function(result) {    ...
    },
    error:function(msg){
      ...
    }
})

  目前都是前后端分离的开发模式,两端通信全靠 json,所以,在发送 post 请求时必须得约定并设置请求头 contentType: "application/json;charset=utf-8"。如果不设置的话,这个请求的 contentType 默认 application/x-www-form-urlencoded,一个 415 + 大红叉 顶给你。

  接着,需要设置 data。在发送请求时,如果写成:data: { name, pwd } 的话,服务器还是会返回 400 错误。其实理由也很简单, http 通信过程中,要么就是字符串,要么就是二进制流 ,而 { name, pwd } 是一个对象,必须先转化成字符串或者流,才能传输。于是在请求中,首先得用 JSON.stringify 将 json 对象转换成字符串,这样,服务器才能正确理解请求并拿到数据。

  综上,在 post 请求中,一定要对这两个属性进行设置和处理。

JSON.parse 和 JSON.stringify

  这两个 api 在前端的应用频率也是相当高的,不过,因为某些原因,对 JSON.stringify 这个 api 理解上有些误差。直到最近在查资料时才有了不一样的领悟。

  JSON.parse 将一个 (json) 字符串转换成 (json) 对象,它有个名字是 反序列化;

  JSON.stringify 作用与 JSON.parse 相反,将对象转化成字符串,所以它也有个名字是 序列化。

  序列化 (Serialization)是将对象的状态信息转换为可以 存储 传输 的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

  尤想起,当年写 class 的时候,序列化与反序列化齐飞,直至今日才明白官方定义...溜了溜了...

POST 常见的数据提交类型 - Content-Type

application/x-www-form-urlencoded

  最常见的 POST 提交数据的方式,原生 form 表单默认的提交方式,同时,如果在 ajax 中不设置的话,同样以这种方式提交。

  这种方式提交的数据会转换成键值对并按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都会进行url 编码。如:

POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8

name=test&val1=1&val2=%E6%B5%8B%E8%AF%95&val3%5B%5D=2

multipart/form-data

  常用于多文件上传。这种方式将表单数据处理成一条消息,以标签为单元,用分隔符(常见的是 boundary)分开。因为这种方式将数据分割为多个部分,所以它既可以上传键值对,也可以上传文件、多文件。当上传的字段是文件时,会有 Content - Type 来说明文件类型;Content-disposition,用来说明字段的一些信息。每部分以 -boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(字段、文本或二进制等)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 -boundary- 标识结束。

  如:(没太看明白)

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"

title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

application/json

  这个头应该会很熟悉,这也是日常用的比较多的请求/响应头。这个消息头的作用是告诉服务端消息主体是序列化后的 JSON 字符串。

  顺手也贴一个:

POST http://www.example.com HTTP/1.1
Content-Type: application/json;charset=utf-8

{"title":"test","sub":[1,2,3]}

text/plain

  这个消息类型是文件已被设置为纯文本形式,浏览器、服务器收到这种类型的数据不会进行进一步的处理,开发者需要自行判断处理。也支持发送 JSON 字符串。

  这个类型意味着消息自由性变大。

text/xml 和 application/xml

  这两消息类型年代久远...至少在 web 前端领域做实际项目的时候完全没有碰到过。以 xml 文档的形式发送数据。不过因为 xml 严谨结构,对 web 前端来说,这会产生更多的流量,基本被弃用。

  然后这两者的区别是前者默认使用 ‘us-ascii’ 字符集编解码,后者默认 ‘utf-8‘ 字符集编解码;前者只能在消息头 content-type 中设置编解码格式才有效,后者在消息头或者在文档内部中设置均可以。

原文地址:https://www.cnblogs.com/cc-freiheit/p/10334755.html

时间: 2024-10-08 22:13:39

由 POST 400 错误拔出来的萝卜的相关文章

HTTP 400 错误 - 请求无效 (Bad request)

在ajax请求后台数据时有时会报 HTTP 400 错误 - 请求无效 (Bad request);出现这个请求无效报错说明请求没有进入到后台服务里: 原因:1)前端提交数据的字段名称或者是字段类型和后台的实体类不一致,导致无法封装: 2)前端提交的到后台的数据应该是json字符串类型,而前端没有将对象转化为字符串类型: 解决方案: 1)对照字段名称,类型保证一致性 2)使用stringify将前端传递的对象转化为字符串    data: JSON.stringify(param)  ;

Yii框架 400 错误

YII  400错误 在YII框架中400错误是csrf校验失败的意思 csrf是什么? CSRF(Cross-site request forgery跨站请求伪造,也被称为"One Click Attack"或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用. 所以,如果你自己没有csrf校验机制,严禁关闭csrf. 怎么关呢? public $enableCsrfValidation=false;  设置 为false为成员变量 如果不关.怎么

Yii2请求,报400错误

出现400错误是yii2.0的csrf防范策略导致 在components里面添加request配置如下: 'request' => [ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 'cookieValidationKey' => '83r5HbITBiMfmiYPOZFdL-raVp4O1VV4', 'enableCookieValid

get请求400错误,post请求405错误

get请求400错误,post请求405错误 (2016-08-31 17:19:27) 转载▼     出现错误原因,后台接收参数part使用的是List,参数的属性对不上,传参使用的类型是String,改为post请求之后才发现 此种错误再次发生,确实是后台接受参数类型和前台所传类型不符,导致400错误 附上错误对应 400 - 错误的请求. ·401 - 访问被拒绝.IIS 定义了许多不同的 401 错误,它们指明更为具体的错误原因.这些具体的错误代码在浏览器中显示,但不在 IIS 日志中

SpringMVC + Spring + MyBatis 学习笔记:提交数据遭遇基础类型和日期类型报400错误解决方法

系统:WIN7 数据库:mysql 开发工具:Eclipse 框架:Spring3.2.9.SpringMVC3.2.9.MyBatis3.2.8 使用SpringMVC开发的时候,页面如果有日期格式的数据,后台接受也是java.util.Date,则报告400错误 . 在controller使用对象来接收前台页面的date数据类型时报400错误 下面是解决方案的演示示例: 这个是实体类,里面createDate就是java.util.Date类型 1 import java.util.Date

Nginx 400错误研究

这几天游戏上线在查看 Nginx 的访问日志时,发现有很多 HTTP 返回码为 400 的记录. 以下是Nginx 的访问日志: 222.89.55.137 - - [27/Dec/2014:19:35:15 +0800] "POST /dia.php HTTP/1.1" 400 172 "-" "-" "-"    网站查了很多文档关于400问题的解决方法: 1.修改nginx配置文件   client_header_buf

解决YII提交POST表单出现400错误,以及ajax post请求时出现400问题

POST表单400错误: 正确做法: Add this in the head section of your layout: <?= Html::csrfMetaTags() ?> ---------------------------------  不推荐的做法,以下做法是取消CSRF令牌验证: Add this in your controller: public $enableCsrfValidation = false; 别的方法: 原来是csrf验证的问题,因为表单是自己写的,在Y

java springMVC 报400错误问题

java springMVC 中如果报400错误 很有可能是因为时间转换的问题. 我在项目中就遇到了这个问题,是因为我少引用了一个库,如果是因为时间问题的话添加以下依赖就可以解决. 1 <dependency> 2 <groupId>joda-time</groupId> 3 <artifactId>joda-time</artifactId> 4 <version>1.3</version> 5 </depende

记一次400错误引发的血案(URL中特殊符号的转义/400 bad request错误)

django+nginx+uwsgi部署的站点访问某个URL时发生了400 bad request的错误,而使用django自带的开发版的web server时没有遇到此问题.初步判断是nginx或uwsgi配置问题. 网上有说是因为request header过大而nginx配置的client_header_buffer_size和large_client_header_buffers过小引起的,但就当前的状态来看感觉不太可能.因为request header并不是特别大.至于是别的什么原因还