在带有 spring-boot rest 和 Swagger 的标头中使用 utf-8 字符时未加载响应

Posted

技术标签:

【中文标题】在带有 spring-boot rest 和 Swagger 的标头中使用 utf-8 字符时未加载响应【英文标题】:Response not loading when using utf-8 chars in header with spring-boot rest and Swagger 【发布时间】:2017-04-16 08:14:04 【问题描述】:

我有招摇的弹簧启动应用程序。当我测试我的休息服务时,标题中没有 utf-8 字符,一切正常。我可以用来测试它的 Swagger 生成命令:

curl -X GET --header 'Accept: application/json' --header 'user: me' --header 'reason: zst' --header 'Authorization: Basic dG9tYXM6dG9tYXMxMjM=' 'http://localhost:8080/my-app/uuid/756531B55A3D029A0894D7C9C4ACDF3EC0'

但是当我大摇大摆地使用 utf-8 字符时,我没有得到任何回应。 Swagger 只是在加载一些东西。当我查看 Firefox 的控制台时,我只看到一些获取请求:

http://localhost:8080/my-app/webjars/springfox-swagger-ui/images/throbber.gif 

没有回应。

当我尝试编辑上面的curl 命令时:

curl -X GET --header 'Accept: application/json' --header 'user: me' --header 'reason: žšť' --header 'Authorization: Basic dG9tYXM6dG9tYXMxMjM=' 'http://localhost:8080/my-app/uuid/756531B55A3D029A0894D7C9C4ACDF3EC0'

一切正常,所以我想我的后端没有问题。有什么方法可以修复/调试这个问题吗?

【问题讨论】:

【参考方案1】:

根据RFC 2616 section 4Message Headers定义如下:

message-header = field-name ":" [ field-value ]
field-name     = token
field-value    = *( field-content | LWS )
field-content  = <the OCTETs making up the field-value
                 and consisting of either *TEXT or combinations
                 of token, separators, and quoted-string>

根据section 2知道:

token          = 1*<any CHAR except CTLs or separators>
separators     = "(" | ")" | "<" | ">" | "@"
                  | "," | ";" | ":" | "\" | <">
                  | "/" | "[" | "]" | "?" | "="
                  | "" | "" | SP | HT
CHAR           = <any US-ASCII character (octets 0 - 127)>
quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
qdtext         = <any TEXT except <">>

TEXT 规则仅用于描述性字段内容和值 不打算由消息解析器解释。 单词 的 *TEXT 可能包含来自 ISO-8859-1 以外的字符集的字符,仅当根据 RFC 2047 的规则进行编码时。

TEXT          = <any OCTET except CTLs,
                but including LWS>    

换句话说,标头的值只能是ISO-8859-1 编码,如果你想对不包含在这个字符集中的字符进行编码,这似乎是这里的情况,你应该根据RFC 2047 也称为 MIME(多用途 Internet 邮件扩展)第三部分:非 ASCII 文本的邮件头扩展

所以不是

reason: žšť

应该是

reason: =?utf-8?q?=C5=BE=C5=A1=C5=A5?=

在实践中,甚至建议您在没有US-ASCII 字符时对值进行编码。

最后要检查的是,您的 JAX-RS 实现是否支持开箱即用的 RFC 2047,如果不支持,则需要手动解码,例如使用实用程序方法MimeUtility.decodeText(String etext).

这是一个具体的例子:

@GET
public Response showHeader(@HeaderParam("reason") String reason) 
    throws UnsupportedEncodingException 
    // Decode it
    reason = MimeUtility.decodeText(reason);
    // Return the value of the decoded String
    return Response.status(Response.Status.OK)
        .entity(String.format("Value of reason = '%s'", reason))
        .build();

使用带有--header 'reason: =?utf-8?q?=C5=BE=C5=A1=C5=A5?='curl 调用此资源方法,结果符合预期:

Value of reason = 'žšť'

注意:要从 js 前端对标头的值进行编码,您可以使用库 q-encoding,这里是 live demo。

【讨论】:

谢谢你的好答案。我会尽快得到你的奖励。只是一个额外的问题。作为前端,我们使用 angular。是否有一些方法可以根据您上面提到的 RFC 对该文本进行编码?

以上是关于在带有 spring-boot rest 和 Swagger 的标头中使用 utf-8 字符时未加载响应的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 中使用带有 Bearer Token 和 form-data 的 Rest Template 调用 REST Api

使用带有elasticbeanstalk,java的rest服务器和websocket,无法连接

WCF Restful 和带有特殊字符的查询字符串

带有REST和Open API的gRPC

如何在带有 Django Rest 框架的 React 前端使用 Django 用户组和权限

带有 django-rest-auth 和 django-rest-knox 的 AttributeError - 令牌序列化器