HTTP POST提交数据方式不同引起的躺坑记

news/2024/7/5 8:44:09 标签: curl, post

post提交数据方式不同引起的躺坑记">HTTP POST提交数据方式不同引起的躺坑记

jasonye 2017-08-12

问题现象:

PHP代码中调用curl POST提交的数据,在Go Server端一直用PostFormValue读不到,但是用curl -d命令提交的数据可以读取到。

定位问题:

在试图采用postman手动post数据到后端看能否重现问题的过程中,无意发现Postman中提供了四种POST提交方式:

  1. application/x-www-form-urlencoded
  2. multipart/form-data
  3. raw
  4. binary

进一步试验发现,不同提交方式到后台结果不一样。采用 application/x-www-form-urlencoded 可以读取到,而 multipart/form-data 读取不到。

进一步发现:这两种提交方式的不同,在数据传输的形式上也是不同的。分别如下:

application/x-www-form-urlencoded如下:

POST /CrowdCal HTTP/1.1
Host: x.x.x.x:xxxx
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Postman-Token: 76d762fa-c06a-6f0f-168f-cabac25f5d11

Fcal_formula=1&Fcal_job_id=206&Fcustom_id=1

而 multipart/form-data:

POST /CrowdCal HTTP/1.1
Host: x.x.x.x:xxxx
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Cache-Control: no-cache
Postman-Token: fa780fa5-ab1e-97bc-0e2b-91e40483412a

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="Fcal_formula"

AA=1&BB=1^C=1
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="Fcal_job_id"

12
------WebKitFormBoundary7MA4YWxkTrZu0gW

于是问题差不多定位到了,是由于前后端PHP代码和GO代码对POST提交数据的解析方式不统一引起的问题。

解决问题:

方法一:
原来PHP代码使用如下方式提交:

curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $arrData);

进一步查看PHP文档解析如下:
CURLOPT_POST : TRUE to do a regular HTTP POST. This POST is the normal application/x-www-form-urlencoded kind, most commonly used by HTML forms.

CURLOPT_POSTFIELDS 提交的第三个参数:
If value is an array, the Content-Type header will be set to multipart/form-data.

并且特别Note:
Passing an array to CURLOPT_POSTFIELDS will encode the data as multipart/form-data, while passing a URL-encoded string will encode the data as application/x-www-form-urlencoded.

于是上面代码修改为这样解决:

$strQuery = http_build_query($arrData);
curl_setopt($ch, CURLOPT_POST, true);
// curl_setopt($ch, CURLOPT_POSTFIELDS, $arrData);
curl_setopt($ch, CURLOPT_POSTFIELDS, $strQuery);

问题解决,改成使用application/x-www-form-urlencoded方式数据,后端就可以正确解析提交的数据了。

方法二:
上面的问题也可以通过GO Server端改变解析POST数据的方式来解决。

Go端原来代码如下:

    r.ParseForm()
    //r.ParseMultipartForm(100)

    fmt.Println("PostFormValue", r.PostFormValue("Fcal_formula"))

查看r.ParseForm文档:
For all requests, ParseForm parses the raw query from the URL and updates r.Form.

For POST, PUT, and PATCH requests, it also parses the request body as a form and puts the results into both r.PostForm and r.Form. Request body parameters take precedence over URL query string values in r.Form.

For other HTTP methods, or when the Content-Type is not application/x-www-form-urlencoded, the request Body is not read, and r.PostForm is initialized to a non-nil, empty value.

PostFormValue returns the first value for the named component of the POST or PUT request body. URL query parameters are ignored. **PostFormValue calls ParseMultipartForm and ParseForm if necessary and ignores any errors returned by these functions. If key is not present, PostFormValue returns the empty string.
**

于是修改去掉 r.ParseForm 就好了。

进一步说明:

上述4中方式,其实是POST的:Form content types 参考[https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4]

HTTP协议默认要求:
User agents must support the content types listed below. Behavior for other content types is unspecified.
application/x-www-form-urlencoded 和 multipart/form-data

其他的的类型并没有要求,但是越来越多的浏览器、WEB站点开始支持
raw类型:
包括:text/plain, appliation/json , appliation/javascript , application/xml , application/html ,application/xml, text/xml 等


binary:即发送二进制文件

POST /pcc HTTP/1.1
Host: 127.0.0.1:8808
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: c30910c3-8371-a472-4b1a-6640e85f4623

{"sfj":{"sfd":"sdff"}}

参考文献:
https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
https://imququ.com/post/four-ways-to-post-data-in-http.html
Go文档、
PHP文档


http://www.niftyadmin.cn/n/739357.html

相关文章

Effecitve C++读书笔记(一)

最近工作中开始又使用C了,而且应用软件的开发C语言确实有了一定的局限。所以还是准备多看一些关于C的书籍,总结下。 视C为一个语言联盟,我个人觉得这是一个绝妙的想法。因为C和C的纠葛不清,但是又因为是一门高级的面向对象的语言…

go语言包管理

包名字可以和目录名字 可以不一样, 但是推荐一样,便于快速查找识别到包,否则容易误解一个目录中只包含一个包、包含多个包会报错一个包可以放在多个文件中、包文件只放在src文件目录下,通过GOPATH引用、否则引用不到。import只要引…

WIN7无线网卡开软AP的方法

l 实现方式一: l 无线网卡的软AP模式,对于经常出差以及学生宿舍等没有无线路由器的场合,不仅能解决燃眉之急,而且也很方便实用。不过在WindowsXP下,需要使用 网卡的驱动程序将无线网卡设置为AP模式,费时费力…

dns应该怎么设置

摘自http://jingyan.baidu.com/article/e8cdb32b87deaa37052bad91.html 有时候DNS无法获取只能通过手动设置,有时候手动设置了DNS反而造成无法上网的问题,这时候又要修改DNS为自动获取,下面我就来介绍一下怎么获取DNS并设置成固定的dns。分为…

团队代码合丢问题回顾

近期服务端这边出现了几次代码合并丢失的问题,结果导致一次线上P1故障,一次推迟试验结果出数据,问题很严重。所以回顾一下,期望以后不要再躺在了同样的坑里面。 近期丢代码事件 A同学误操作将测试中dev分支合并到master&#xf…

WIFI基本知识

摘自http://blog.chinaunix.net/uid-9525959-id-3326047.html 这里对wifi的802.11协议中比较常见的知识做一个基本的总结和整理,便于后续的学习。因为无线网络中涉及术语很多,并且许多协议都是用英文描述,所以有些地方翻译出来会有歧义&#…

怎么进行CodeReview

怎么进行Code review? 需求 功能是什么?功能之外的需求 可用性/易用性、可测试、目标性能、安全性、扩展性、可用性等监控、打点 设计 1. 方案设计是否合理 表定义:是否需要分库/分表?根据业务预期增长情况考虑、2~3年缓存…

教你学用CURL命令 --- 命令行浏览器

转载自 http://bbs.et8.net/bbs/showthread.php?t568472 CURL? 嗯,说来话长了~~~~ 这东西现在已经是苹果机上内置的命令行工具之一了,可见其魅力之一斑 1) 二话不说,先从这里开始吧! curl http://www.yahoo.com 回车之后&am…