Laravel Tutorial

Bài 13: Response trong Laravel

Response là các thông tin phản hồi cho người dùng. Qua đó biết được Request gửi tới Server có tình trạng như thế nào. Response thường gặp nhất đó là 404 khi bạn truy cập vào một địa chỉ website do mất kết nối thường xuất hiện 404. Trong Laravel tất cả các route hay controller đều phải trả về một response. Laravel có cung cấp sẵn một Response class để hỗ trợ chúng ta trả về các loại response data một cách đơn giản nhất. Lệnh Request có thể được viết tại Controller hoặc route

1. Tạo response (Creating response)

# Chuỗi và mảng (String and array)

Mặc định, Khi một route, controller trả về giá trị là chuỗi thì Laravel sẽ tự động convert nó về dạng một HTTP response

routes/web.php

Route::get('/', function () {
   return 'Hello World!';
});

Kết quả

Ngoài việc trả về chuỗi từ route hoặc controller , bạn có thể trả về một mảng. Laravel sẽ tự động chuyển mảng đó về JSON response

routes/web.php

Route::get('/', function () {
   return [1, 2, 3];
});

Kết quả

# Đối tượng response (Response object)

Tuy nhiên, trong thực tế chúng ta lại cần trả về response với các header, status khác nhau. Lúc này bạn có thể sử dụng Response (Illuminate\Http\Response) của Laravel. Đồng thời Laravel cũng có đưa Response class vào helper. Nên chúng ta hoàn toàn có thể sử dụng hàmresponse() trong helper thay cho Response class để code được ngắn gọn hơn

Route::get('/', function () {
   return response('Hello World', 200)->header('Content-Type', 'text/plain');
});

Ta đã thiết lập status code HTTP response là 200 thông qua tham số thứ hai của method response. Ngoài ra còn đính kèm header Content-Type: text/plain bằng phương thức header kế tiếp

Kết quả

# Đính kèm header vào response (Attaching header to response)

Tất cả các method response có thể kết nối được, cho phép bạn xây dựng bất kỳ trường hợp response nào. Chẳng hạn bạn có thể thêm hàng loạt header với method header trước khi trả về người dùng

return response($content)
   ->header('Content-Type', $type)
   ->header('X-Header-One', 'Header Value')
   ->header('X-Header-Two', 'Header Value');

Hoặc thay vì kết nối nhiều method như vậy, bạn có thể sử dụng method withHeaders để truyền nhiều header dưới dạng mảng

return response($content)
   ->withHeaders([
      'Content-Type' => $type,
      'X-Header-One' => 'Header Value',
      'X-Header-Two' => 'Header Value',
]);

# Đính kèm cookie cho response (Attaching cookie to response)

Nếu bạn muốn thêm cookie vào response bạn có thể sử dụng phương thức cookie với cú pháp truyền vào tương tự như đối với hàm setcookie của PHP

return response($content)->cookie('name', 'value', $minutes);  
   

Nếu bạn muốn xóa một cookie nào đó trong response bạn có thể sử dụng phương thức withoutCookie

return response('Hello World')->withoutCookie('name');

2. Chuyển hướng (Redirect)

Đối với trường hợp bạn muốn trả về một redirect response, Laravel cũng có sẵn cho bạn một class Illuminate\Http\RedirectResponse để làm điều đó. Đồng thời Laravel cũng đã đưa nó vào helper để tiện cho việc sử dụng. Chúng ta có thể sử dụng helper redirect thay cho class trên

# Chuyển hướng đến URI (Redirecting to URI)

Ví dụ: Redirect về URL /home/dashboard khi người dùng vào URL /dashboard

Route::get('/dashboard', function () {
   return redirect('home/dashboard');
});

Thỉnh thoảng bạn muốn khi người dùng submit form mà bị lỗi thì chuyển về trang trước để người dùng kiểm tra lại. Chúng ta sử dụng method back, cùng với withInput để đáp ứng yêu cầu trên

Route::post('/user/profile', function () {
   // Validate the request...
   return back()->withInput();
});

# Chuyển hướng đến route được đặt tên (Redirecting to named route)

Cú pháp:

return redirect()->route('name_route');

Ví dụ:

Route::get('/', function() {
   return redirect()->route('home');
});
Route::get('/home', function() {
   return 'Home page';
})->name('home');

Khi mình truy cập route / thì sẽ redirect đến route có name là home

Nếu URI route của bạn chứa tham số, bạn có thể truyền dữ liệu thông qua tham số thứ hai dưới dạng mảng

Route::get('/', function() {
   return redirect()->route('profile', ['id' => 1]);
});

Route::get('/profile/{id}', function($id) {
   return 'Profile '. $id;
})->name('profile');

Khi truy cập: http://localhost:8000. Kết quả là: Profile 1

Nếu bạn không muốn truyền giá trị ID theo mặc định, bạn có thể thay đổi bằng cách khai báo phương thức getRouteKey ở trong file model để thay đổi key ID mặc định

public function getRouteKey()
{
   return $this->slug;
}

# Chuyển hướng đến controller action (Redirecting to controller action)

Bạn có thể tạo chuyển hướng đến route chứa controller action thông qua method action. Việc của bạn là chỉ cần truyền tên controller và tên method chứa trong route muốn chuyển đến

App/Http/Controllers/HomeController.php
<?php
namespace App\Http\Controllers;
class HomeController extends Controller
{
   public function show()
   {
      return "Home page";
   }
}
?>

routes/web.php

use App\Http\Controllers\HomeController;
Route::get('/', function() {
   return redirect()->action([HomeController::class, 'show']);
});
Route::get('/home', [HomeController::class, 'show']);

Khi truy cập: http://localhost:8000. sẽ chuyển hướng đến http://localhost:8000/home. Kết quả là: Home page

# Chuyển hướng đến tên miền bên ngoài (Redirecting to external domain)

return response()->away('https://google.com');

# Chuyển hướng với flash session (Redirecting with flash session)

Redirect đến một URL mới và flash session thường được thực hiện cùng một lúc. Chẳng hạn bây giờ mình đăng ký hai route như sau:

routes/web.php

Route::get('/', function() {
   return redirect('home')->with('name', 'John');
});

Route::get('/home', function() {
   return view('home');
});

Tại action của route /, ta thực thi chuyển hướng đến URI /home, đồng thời thực hiện flash session với method with. Sau khi chuyển hướng thì flash session data được thiết lập, lúc này bạn chỉ cần lấy nó ra và sử dụng thôi

resources/views/home.blade.php

<h3>
   @if (session('name'))
      Welcome, {{ session('name') }}
   @else
      Welcome
   @endif
</h3>

Khi truy cập: http://localhost:8000. sẽ chuyển hướng đến http://localhost:8000/home. Kết quả là: John

Còn nếu truy cập thẳng đến http://localhost:8000/home. Kết quả là: Welcome

3. Các loại response khác (Other response types)

Nếu bạn cần kiểm soát status codeheader của  và cũng muốn trả lại nội dung của response, bạn nên sử dụng method view:

Cú pháp:

return response()
   ->view('hello', $data, 200)
   ->header('Content-Type', $type);

$data: Dữ liệu truyền vào views

200: status code

Ví dụ

routes/web.php

Route::get('/', function() {
   return response()->view('hello', $data = ['name'=>'John'], 200)                   
});

resources/views/hello.blade.php

<h3>Hello {{ $name }}</h3>

Kết quả

# JSON response

Phương thức json sẽ tự động set Content-type: application/json, chuyển đổi các mảng về dạng JSON sử dụng phương thức json_encode của PHP

routes/web.php

Route::get('/', function() {
   return response()->json([
      'name' => 'Nguyễn Văn Hứa',
      'state' => 'VN'
   ]);
});

Kết quả

Nếu muốn tạo JSONP response, bạn có thể sử dụng phương thức json cùng với withCallback

Route::get('/', function(Request $request) {
   return response()
      ->json(['name' => 'Abigail', 'state' => 'CA'])
      ->withCallback($request->input('callback'));
});

# Download file

Method download thường được sử dụng để tạo một response bắt buộc người dùng download một file tại đường dẫn nhất định

return response()->download($pathToFile);

return response()->download($pathToFile, $name, $headers);

Trong đó:

  • $pathToFile là path đến file bạn muốn trả về.
  • $name là tên của file bạn muốn trả về.
  • $headers là các header bạn muốn trả về kèm theo

Ví dụ: download file resources/views/abc.blade.php 

Route::get('/download', function() {
   return response()->download('../resources/views/abc.blade.php');
});

Nếu bạn muốn một cái tên khác khi download, có thể thêm tham số thứ hai như sau:

Route::get('/download', function() {
   return response()->download('../resources/views/abc.blade.php','other_file.php');
});

Bạn có thể khai báo các header theo dạng cấu trúc mảng

$headers = [
    'X-Header-One' => 'Header value 1',
    'X-Header-Two' => 'Header value 2',
    // ...
];

Ngoài ra bạn có thể xóa file ngay sau khi người dùng download bằng cách sử dụng method deleteFileAfterSend

return response()->download($pathFile, $nameFile, $headers)->deleteFileAfterSend();

# Streamed download

Đôi khi bạn muốn trả về một nội dung nào đó có thể download được, nhưng lại không muốn ghi chúng vào ổ trước khi download. Bạn có thể sử dụng method streamDownload để trả về một stream data

return response()->streamDownload(Closure, $nameFile, $headers);

Trong đó:

  • Closure có nhiệm vụ thực hiện xử lý để echo nội dung cho file.
  • $name: Tham số thứ hai là tên file download.
  • $headers: Tham số thứ ba (tùy chọn) là các thiết lập header

routes/web.php

Route::get('/stream', function() {
   return response()->streamDownload(function() {
      echo 'Nguyễn Văn Hứa';
   }, 'users.txt');
});

Lưu ý: Bắt buộc phải dùng lệnh echo thì nội dung mới ghi được trên file download. Nội dung của file chỉ được là dạng text

Nội dung file users.txt sau khi tải về sẽ là: Nguyễn Văn Hứa

# File response

Nếu bạn muốn trả về response của các image, pdf… để hiển thị trên trình duyệt người dùng thay vì tải về, bạn có thể sử dụng method file

return response()->file($pathFile, $headers);

Trong đó:

  • $pathFile: path file cần hiển thị
  • $headers: tùy chọn chứa mảng thiết lập header response

Lưu ý: Base path của đường dẫn file trong method file cũng là public giống như method download

Ví dụ: Thêm một ảnh cai-dat-laravel.png vào  folder public

routes/web.php

Route::get('/image', function() { 
   return response()->file('cai-dat-laravel.png'); 
});

Kết quả

# Reponse macro

Nếu bạn muốn định nghĩa một response tùy chỉnh mà bạn có thể sử dụng lại trong nhiều routescontrollers của mình, bạn có thể sử dụng method macro

Bạn có thể tạo một service provider với tên ResponseMacroServiceProvider  tại method boot bạn sẽ thực hiện việc định nghĩa các custom response

Ví dụ: Tạo một response để có thể trả về chuỗi in hoa, mình sẽ đăng ký với macro như sau:

App/providers/ResponseMacroServiceProvider

<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Response;
class ResponseMacroServiceProvider extends ServiceProvider {
   public function boot()
   {
      Response::macro('caps', function ($value) {
         return Response::make(strtoupper($value));
      });
   }
}
?>

Method Response::macro: dùng để định nghĩa một custom response

  • Tham số thứ nhất sẽ là tên của custom response.
  • Tham số thứ hai sẽ là một Closure, nhận dữ liệu truyền về qua $value.

Method Response::make: dùng để tạo response, nó sẽ nhận tham số là các chuỗi xử lý $value trước khi được trả về.

Liệt kệ service provider vừa tạo trong config/app.php 

'providers' => [
   ...
   App\Providers\ResponseMacroServiceProvider::class
],   

Giờ đây có thể sử dụng response caps như những các loại response khác.

routes/web.php

Route::get('caps/{str}', function($str) {
   return response()->caps($str);
})

Kết quả

 

Leave a Comment