问题的提出
做Web开发,经常需要对API进行测试,这个时候比较方便的工具就是使用Postman了,Postman上有3种基本方式向服务器发送数据
– application/x-www-form-urlencoded
– multipart/form-data
– application/json
到底选择哪一个呢?
另外,作者最近参与一个Prometheus监控web api的一个项目也遇到了一个问题,是应该写死Content-Type还是让用户可以自行配置呢?
以上两个问题实际上是同一个问题,那就是以上几个content-type的区别了。
x-www-form-urlencoded
用这种方式发送数据的时候,如果有多条数据发送,最终会变成&连接起来的“key=value”串,例如如果发送下面的x-www-form-urlencoded请求,最终发送的数据就会是(pageId=3&locale=zh-Hans-CN),这个有点类似于get请求中的url参数。
form-data
通常情况下会用这种方式上传文件到服务器,例如图片、视频等
application/json
这种情况下,数据会以Json字符串的形式发送。
API实现上的差异
以上分析了3种方式的区别,但是实际在测试API的时候Content-Type到底是用application/json还是application/x-www-form-urlencoded呢?其实这两个到底用哪个是在服务器端决定的。主要是看API的实现用的是哪种方式解析POST过来的参数。
下面是一个最简单的Flask实现的POST API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import json from flask import request from flask import Flask from flask import jsonify app = Flask(__name__) @app.route('/apitst', methods=["POST"]) def apitst(): # parse json data print json.loads(request.data) # parse form data d = request.form print d['locale'] print d['pageId'] return jsonify({'ret': 'ok'}) if __name__ == '__main__': app.run(host="0.0.0.0", threaded=True, debug=False, port=5000) |
可以看到,如果API实现是用load request.data种的json字符串的方式来获取参数,则需要将Content-Type设定为application/json,如果是通过解析request.form来获取参数,则需要将Content-Type设定为application/x-www-form-urlencoded
当然如果服务器需要接受的参数,不是简单的key/value对,而是复杂的嵌套结构,当然就需要用json的方式来解析。
代码调用方面的差异
下面是Python请求两种类型的API实现上的差异,如果Content-Type设定为application/json,则发送的数据需要dump为json字符串,而不是原始的json类型。而x-www-form-urlencoded则需要使用原始json类型。否则服务器解析会出错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import requests import json headers = {'Content-Type': 'application/x-www-form-urlencoded'} payload = { 'locale': 'en-us', 'pageId': 1 } requests.post("http://127.0.0.1:5000/apitst", data=payload, headers=headers) headers = {'Content-Type': 'application/json'} requests.post("http://127.0.0.1:5000/apitst", data=json.dumps(payload), headers=headers) |