Laravel:将JSON响应编码为UTF-8

12

我想将我的API的JSON响应编码为UTF-8,但每次做出响应时我都不想这样做:

return response()->json($res,200,['Content-type'=>'application/json;charset=utf-8'],JSON_UNESCAPED_UNICODE);

所以我考虑为所有API路由制作一个中间件,handle(...)函数将是这样的:

public function handle($request, Closure $next) {
    $response = $next($request);
    $response->header('Content-type','application/json; charset=utf-8');
    return $next($request);
}
问题在于它无法工作,我的响应的Content-type头仍为application/json而不是application/json; charset=utf-8; 可能是因为json(...)函数已经设置了一个Content-type头,并且我无法覆盖它。

我该怎么办呢?

感谢您的帮助。


你需要反过来做,你想使用中间件之后的步骤。 - Kyslik
我不明白你的意思。 - JacopoStanchi
1
$request->header('key', 'default') 是一行中的 getter,你正在执行 NOP(无操作)。 - Kyslik
你是对的。我添加了 $response = $next($request); 并将 $request 替换为 $response,但头部没有改变。 - JacopoStanchi
3个回答

32

文档中已经有了,你需要使用after中间件(下面代码是我临时想到的示例,应该可以工作):

在文档中已经有说明,您需要使用after中间件(以下代码来自我的头脑,应该可以工作):

<?php

namespace App\Http\Middleware;

use Closure;

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {

        /** @var array $data */ // you need to return array from controller
        $data = $next($request);

        return response()->json($data, 200, ['Content-Type' => 'application/json;charset=UTF-8', 'Charset' => 'utf-8'],
        JSON_UNESCAPED_UNICODE);
    }
}

通过上述方法,我们可以发现两个反模式:

  • 首先,中间件中制作响应(应该在控制器中完成)。

  • 此外,可能应避免使用未转义的JSON响应,因为Laravel创建者将“转义为纯文本”设置为默认值,但如果您的Web-API的客户端应用程序都支持UTF-8,则取消转义可以提高性能。 体验表明,大多数客户端不仅支持它,而且还假定如果Content-Type标题中缺少charset,则采用UTF-8

    Experience shows that most clients beside supporting it, they even assume UTF-8 if charset is missing from Content-Type header.

删除中间件并仅使用控制器

将以下代码放入app/Http/Controller.php中。

protected function jsonResponse($data, $code = 200)
{
    return response()->json($data, $code,
        ['Content-Type' => 'application/json;charset=UTF-8', 'Charset' => 'utf-8'], JSON_UNESCAPED_UNICODE);
}

在任何一个继承了基础控制器(app/Http/Controller.php)的控制器中,您都可以使用$this->jsonResponse($data);

专业人士是如何做到的

他们使用Eloquent资源或者如果需要更多功能,则使用Fractal(在Laravel中使用spatie包装器 - https://github.com/spatie/laravel-fractal)。


好的,但是我该如何传递HTTP状态? - JacopoStanchi
没错!你想使用了错误的工具。我正在更新我的答案,请耐心等待。 - Kyslik
详细而直接,继续加油 @Kyslik - Parth Pandya
你好,我该如何在中间件中传递我的“状态码”? - HardCoder
1
非常有帮助,谢谢! - Morgenstern
但是你如何在资源中使用utf8? - NicoHood

0
在你的JsonResource类中只需添加以下内容:
/**
 * Customize the outgoing response for the resource.
 *
 * @param  \Illuminate\Http\Request
 * @param  \Illuminate\Http\Response
 * @return void
 */
public function withResponse($request, $response)
{
    $charset = $request->header('Accept-Charset', 'utf-8');
    if ($charset === 'utf-8') {
        $response->header('Charset', 'utf-8');
        $response->header('Content-Type','application/json; charset=utf-8');
        $response->setEncodingOptions(JSON_UNESCAPED_UNICODE);
    }
    // Alternative: iso-8859-1 which will be encoded by default using json escaping.
}

我想指出,当同时使用单个资源和集合时,你必须为两者都实现这一点:JsonResourceResourceCollection。像EventResource::collection($events->get())这样使用是不起作用的。

来源:Github


0
对于Flutter移动应用程序,我们使用jsonDecode(response.data)来解码接收到的响应。所以在这里我正在使用。
$response = array();
$response['status] = 200;
$response['data] = $data;
echo json_encode($response);

在这个Flutter应用程序开发代码中,你可以使用以下方法解码接收到的响应。
var json = jsonDecode(response.data)

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