在HTTP头中使用JSON字符串

35

最近我在使用HTTP头时遇到了一些奇怪的问题(添加多个自定义HTTP请求头的谜团)。当时为了避免这个问题,我把字段放到JSON字符串中,然后将该JSON字符串添加到头部,而不是将这些字段添加到单独的HTTP头。

例如,不是这样做:

request.addHeader("UserName", mUserName);
request.addHeader("AuthToken", mAuthorizationToken);
request.addHeader("clientId","android_client");

我创建了一个 JSON 字符串并将其添加到单个标头中。

String jsonStr="{\"UserName\":\"myname\",\"AuthToken\":\"123456\",\"clientId\":\"android_client\"}";
request.addHeader("JSonStr",jsonStr);

因为我刚开始写Rest和处理Http的东西,不知道我的用法是否正确。希望能得到一些见解。

一些链接

http://lists.w3.org/Archives/Public/ietf-http-wg/2011OctDec/0133.html


只是好奇:您在请求正文中发送了什么内容,使用头部传输数据? - Bergi
1
这是HttpGet请求。我没有在请求体中发送任何内容。 - Win Myo Htet
将整个主要对象编码为URL友好格式,将其放入查询字符串中。需要使用时解码和解析。 - rocketspacer
2
如果你真的需要在头部设置它,那么在设置头部之前对整个JSON字符串进行base64编码。 - rocketspacer
1
我认为这是一个有趣的想法。我猜测您正在通过标头传递身份验证数据。由于身份验证数据可能与您的请求目的/意图无关,而仅仅是一种前导或元数据,因此我认为它很适合放在标头中。 - Aquarelle
5个回答

44

是的,在一些限制下您可以在HTTP头部使用JSON。

根据HTTP规范,您的标头字段内容只能包含可见ASCII字符、制表符和空格。

由于许多JSON编码器(例如PHP中的json_encode)会对不可见或非ASCII字符进行编码(例如“é”变成“\u00E9”),因此通常您不需要担心这个问题。

但请检查您特定编码器的文档或进行测试,因为JSON字符串在技术上允许大多数Unicode字符。例如,在JavaScript中,JSON.stringify()默认情况下不转义多字节Unicode。不过,您可以轻松地修改它来实现转义,例如:

var charsToEncode = /[\u007f-\uffff]/g;
function http_header_safe_json(v) {
  return JSON.stringify(v).replace(charsToEncode,
    function(c) {
      return '\\u'+('000'+c.charCodeAt(0).toString(16)).slice(-4);
    }
  );
}

来源

另外,您可以像@rocketspacer建议的那样,在将其插入标头字段之前对JSON进行base64编码(例如JWT如何执行)。 这将使JSON在标头中无法被人类阅读,但确保其符合规范。


值得注意的是,原始的ARPA规范(RFC 822)对这个确切的用例有一个特殊的描述,并且这种精神在后续的规范中(如RFC 7230)也有所体现:

某些标头的字段正文可能根据一些系统希望解析的内部语法进行解释。

此外,RFC 822和RFC 7230明确没有长度限制:

HTTP不会对每个标头字段或整个标头部分的长度设置预定义的限制,如第2.5节所述。


2
请问,将JSON发送到头部是否是一个好的做法?这两种方法有什么区别?用哪种方法在什么时候比较合适? - Turkhan Badalov

17

发送之前先对其进行Base64编码,就像JSON Web Token的做法一样。
以下是一个Node.js示例:


以下是一个Node.js示例:

const myJsonStr = JSON.stringify(myData);
const headerFriendlyStr = Buffer.from(myJsonStr, 'utf8').toString('base64');
res.addHeader('foo', headerFriendlyStr);

需要阅读时进行解码:

const myBase64Str = req.headers['foo'];
const myJsonStr = Buffer.from(myBase64Str, 'base64').toString('utf8');
const myData = JSON.parse(myJsonStr);

6
一般来说,在REST API中不会在头部发送数据。如果需要发送大量数据,则最好使用HTTP POST,并将数据发送到请求的正文中。但是,您似乎正在尝试在标题中传递凭据,这是一些REST API使用的方法。这里有一个用于通过名为SMSIfied的服务传递REST API凭据的示例,它允许您通过互联网发送短信文本消息。此示例使用基本身份验证,这是REST API的常见技术。但是,您需要使用SSL技术使其更加安全。这里有一个示例,说明如何使用WCF和REST实现基本身份验证。

我已经完成了认证部分。http://stackoverflow.com/q/9643115/319058 我更关心的是分析我在头部使用JSON字符串的方式。 - Win Myo Htet
1
根据我的回答,请勿在头部发送数据(JSON或XML)。使用POST并将数据放入请求正文中。如果必须使用GET,则将数据放入URL查询字符串中。设计REST API时,使用GET读取数据(即不对服务进行状态更改),并使用POST插入或更新数据。 - Kevin Junghans
我可以理解在头部没有XML,因为XML相当臃肿,但JSON不同。它是轻量级的。(因此,在提供的邮件线程存档中建议使用它)我在头部放置的是授权令牌,用于验证用户身份。我在这里不做任何状态更改。 - Win Myo Htet
参考线程中的提案尚未被接受。您说您有认证部分,但我看到的安全机制都没有在标头中使用明文JSON。为了更好地讨论REST安全性,我建议查看此帖子https://dev59.com/-3VD5IYBdhLWcg3wWaNh。最好使用现有的HTTP相关安全标准,例如基本身份验证,它使用标头中的编码字符串进行凭据验证,并使用TSL进行传输。 - Kevin Junghans
我在这里做的一切都是通过 https 进行的。我相信您已经知道 https 加密,包括 https://dev59.com/znVC5IYBdhLWcg3wxEN1 中的头信息。 - Win Myo Htet
显示剩余2条评论

5
据我所知,在头部选项中使用JSON字符串并不像使用HTTP DELETE进行HTTP GET那样滥用用法,因此甚至已经提出了在HTTP头部中使用JSON的建议。当然,更全面的见解仍然值得欢迎,接受的答案还有待给出。

2
在设计优先的时代,OpenAPI规范提供了另一个视角
  • HTTP头参数可以是对象, 例如对象X-MyHeader是

    {"role": "admin", "firstName": "Alex"}

  • 然而,在HTTP请求/响应中,该值会被序列化,例如

    X-MyHeader: role=admin,firstName=Alex


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接