Tập 16: Request Laravel
https://viblo.asia/p/tap-16-request-laravel-aWj534Y8K6m
Tập 16: Request Laravel
Rất vui được gặp lại tất cả các bạn trong series "Hành trình chinh phục Laravel framework" của mình. Trong tập ngày hôm nay, chúng ta sẽ cùng nhau tìm hiểu về "Request", nói tìm hiểu thì không hợp lý cho lắm vì chắc ai cũng biết nó là gì rồi. Ở bài này, mình sẽ hướng dẫn các bạn cách sử dụng, khai thác một HTTP request trong Laravel.
I. Truy cập request (Accessing the request)
Để có được object request hiện tại thông qua denpendency injection, bạn cần type-hint Illuminate\Http\Request
class trên controller method. Object request sẽ tự động inject bởi service container.
1. Dependency injection & Route parameters
Như đã đề cập ở các tập trước, nếu trong method controller có nhận các dữ liệu từ tham số URI, thì nên khai báo chúng sau các dependency class. Chẳng hạn bạn có route sau:
Bạn có thể inject Illuminate\Http\Request
class và lấy dữ liệu tham số id
theo cách sau:
Như bạn thấy, ta sẽ ưu tiên inject dependency class trước các tham số trong route.
2. Truy cập request thông qua Route Closure (Accessing the request via route closure)
Nếu việc xử lý logic quá ngắn gọn, bạn có thể inject Iluminate\Http\Request
tại file route như thế này:
II. Request path & Method
Illuminate\Http\Request
cung cấp cho chúng ta rất nhiều method để kiểm tra HTTP request hiện tại. Dưới đây là một số các method quan trọng, hay sử dụng.
1. Lấy request path (Retrieving the request path)
Với method path
sẽ trả về path của request hiện tại. Nếu request hiện tại có url là http://domain.com/foo/bar
thì method path
sẽ trả về foo/bar
.
Các bạn có thể dùng đoạn code trên để test.
Method is
cho phép bạn xác thực rằng request path hiện tại khớp với pattern mà bạn đưa ra. Bạn có thể sử dụng ký tự *
để làm đại diện cho các thành phần phía sau.
Pattern ở đây chính là admin/*
, nếu ta truy cập request path admin/post
thì chắc chắn sẽ trùng khớp.
2. Lấy request URL (Retrieving the request URL)
Để lấy đầy đủ URL của request hiện tại, bạn có thể sử dụng method url
hoặc fullUrl
. Tuy nhiên method url
sẽ trả về URL không chứa query string, còn đối với fullUrl
sẽ trả về URL kèm với query string.
Để có thể hiểu hơn về sự khác biệt này, các bạn đăng ký route fallback như sau:
Ở đây mình đăng ký route fallback để có thể test với bất kỳ đường dẫn nào. Mình truyền hai method url
và fullUrl
vào trong một mảng rồi sau đó dump ra trình duyệt để dễ dàng quan sát.
Các bạn nạp server và truy cập đường dẫn http://localhost:8000/post?id=1 chẳng hạn, đây là kết qua chúng ta thu nhận được:
3. Lấy request method (Retrieving the request method)
Cái này thì khá dễ hiểu, ta chỉ cần sử dụng phương thức method
để lấy method HTTP hiện tại của request. Ngoài ra, ta có thể kiểm tra method HTTP của request hiện tại bằng phương thức isMethod
với tham số truyền vào là method HTTP bạn muốn khớp với method HTTP của request hiện tại.
Một kết quả mong đợi:
III. Chuẩn hóa input (Input normalization)
Mặc định thì Laravel đã kết nối hai middleware TrimStrings
và ConvertEmptyStringsToNull
trong ứng dụng. Các middleware này được liệt kê trong lớp App\Http\Kernel
, cụ thể tại $middleware
. Các middleware này có chức năng sẽ tự động trim
tất cả các trường chứa chuỗi trên request, hơn thế nữa là chuyển đổi bất kỳ trường trống nào về giá trị null
. Với nó, bạn sẽ không cần phải quá lo lắng về việc chuẩn hóa input trong route hay controller nữa.
Nếu bạn muốn vô hiệu hóa hai middleware này, bạn có thể xóa nó khỏi $middleware
tại class App\Http\Kernel
.
IV. Lấy dữ liệu input (Retrieving input data)
Đầu tiên các bạn tạo controller FormController
để ta tiến hành lấy dữ liệu input trong đó. Trong FormController
bạn định nghĩa hai method dưới:
Trong method post
mình đã inject Illuminate\Http\Request
để có thể lấy dữ liệu input từ request hiện tại. Tạm thời ta sẽ để đây, lát ta sẽ tiến hành test sau.
Tiếp đến là đăng ký 2 route:
Cuối cùng là tạo blade view form
để build các form HTML cho việc gửi data từ input. Thế là việc chuẩn bị đã hoàn tất, giờ ta tiến hành test các method hay sử dụng để lấy input từ Illuminate\Http\Request
.
1. Lấy tất cả dữ liệu input (Retriveing all input data)
Tại blade view form
, các bạn tạo form như sau:
Tiếp theo tại method post
của FormController
, ta sẽ thử lấy dữ liệu của tất cả input được gửi từ request bằng cách:
Chúng ta sử dụng method all
để thực thi việc này. Đây là kết quả:
Chú ý: Bạn có thể sử dụng method
input
để thay thế choall
.
2. Lấy dữ liệu của một input (Retriveing an input data)
Vẫn giữ nguyên blade view form
, tại method post
của FormController
ta dump lệnh sau:
Để có thể lấy dữ liệu của một input nào đó trong request hiện tại, ta chỉ cần sử dụng method input
với tham số là tên của input cần lấy trong HTML. Kết quả thu được là:
Ngoài ra, bạn có thể gán giá trị mặc định cho một input nào đó nếu như nó không xác định trong request hiện tại. Chẳng hạn lấy form trên thì mình chẳng có cái input nào tên là remember
cả. Nhưng mình muốn kể cả khi không nó không tồn tại thì vẫn có được giá trị là true
. Để làm thế, mình chỉ cần thêm tham số thứ hai của method input
là giá trị mặc định mà mình muốn gán cho nó.
Nếu bạn làm việc với các array input, sử dụng ký hiệu .
để tham chiếu đến các phần tử của nó. Chẳng hạn giờ mình sẽ thay đổi blade view form
như sau:
Đây là form mô phỏng đăng các sản phẩm lên shop online. Như bạn thấy, các thông tin của sản phẩm đều chứa name là products
dạng mảng.
Giờ ta thử dump data của input products
này bằng cách:
Chúng ta sẽ nhận được một mảng dữ liệu trả về của các input sau khi nhập thử dữ liệu:
Nếu bạn muốn lấy thông tin của sản phẩm có index 0
thì bạn sử dụng cú pháp tham chiếu sau:
Nếu bạn chỉ muốn lấy name
của tất cả sản phẩm trong products
thì có thể là như sau:
3. Lấy dữ liệu input từ chuỗi truy vấn (Retriveing input data from query string)
Trong khi method input
dùng để lấy dữ liệu từ input trong request hiện tại (bao gồm cả query string) thì method query
chỉ lấy giá trị từ query string.
Các bạn thay đổi blade view form
như sau:
Các bạn thấy mình đã truyền query string id=1
cho action
. Để lấy query id
, tại method post
của FormController
ta thực hiện cú pháp sau:
Và đây là kết quả:
4. Lấy dữ liệu input thông qua thuộc tính động (Retrieving input via dynamic properties)
Bạn có thể lấy các dữ liệu input thông qua các thuộc tính trên lớp khởi tạo Illuminate\Http\Request
. Thay vì:
Bạn có thể sử dụng cú pháp:
Nếu như không tồn tại input có được tham chiếu thì nó sẽ lấy giá trị tham số route có tên trùng với tên thuộc tính, còn nếu không tồn tại cả hai thì nó sẽ trả về giá trị là null
.
5. Lấy giá trị JSON input (Retrieving JSON input value)
Chẳng hạn chúng ta có blade view form
như sau:
Như đoạn code trên thì sau khi click "Submit", chúng ta sẽ thực thi ajax đã gửi request có kèm data json user
tới controller.
Tại controller FormController
, để tham chiếu data json user
này, ta thực hiện như sau:
Chúng ta tham chiếu đến các phần tử trong JSOn như là array input ở phần trên.
6. Lấy một phần dữ liệu input (Retrieving a portion of input data)
Ta có thể dùng phương thức only
hoặc except
để lấy một phần dữ liệu input tại request, các phương thức này vừa chấp nhận liệt kê tham số, cũng vừa chấp nhận mảng.
7. Kiểm tra nếu có giá trị input (Checking if has input value)
Bạn có thể sử dụng method has
để kiểm tra sự tồn tại của một input trên request. Nếu có tồn tại sẽ trả về true
.
Lưu ý: Trường hợp có tồn tại input trong HTML nhưng có giá trị
null
thì methodhas
vẫn chấp nhận và trả vềtrue
.
Bạn có thể kiểm tra nhiều input cùng lúc như sau:
Còn nếu bạn muốn kiểm tra input gửi đến có rỗng hay không thì dùng method filled
.
Trong trường hợp này nếu input có giá trị null
hoặc không tồn tại thì sẽ trả về false
.
8. Old input
Laravel cho phép chúng ta giữ input data của request trong request kế tiếp. Tính năng này cực kỳ hữu ích cho việc điền lại các form khi submit gặp lỗi.
Trước khi tìm hiểu thì ta hãy phân tích thuật ngữ "flash session" đã. Thông thường các session sẽ được giới hạn bởi thời gian nhất định, hoặc kéo dài cho tới khi kết thúc phiên làm việc của trình duyệt... Nhưng đối với flash session, "tuổi thọ" của nó chỉ kéo dài trong một request. Tức là tại request nào đó, flash session sẽ được khởi tạo, tới request tiếp theo, nó được sử dụng làm việc gì đó rồi sau đó bị xóa bỏ.
a. Flash input đến session (Flash input to the session)
Method flash
trong lớp Illuminate\Http\Request
sẽ flash input data trong request hiện tại đến session để có thể sử dụng lại trong request kế tiếp. Nếu bạn muốn tất cả input đều flash thì có thể cho dòng code này trước khi bắt đầu xử lý logic trong controller.
Bạn có thể sử dụng hai method flashOnly
và flashExcept
để có thể lọc các input mà bạn muốn flash session.
b. Flash input rồi chuyển hướng (Flash input then redirecting)
Thông thường khi cho user điền một form nào đó quá dài, nhưng nếu xảy ra lỗi, bạn muốn quay trở lại và thông báo một lỗi nào đó mà không phải mất hết các dữ liệu của form. Laravel cung cấp một lệnh chuyển hướng kèm theo flash input để ta có thể giải quyết yêu cầu này.
Method back
sẽ giúp ta chuyển hướng đến url đã truy cập trước đó, còn phương thức withInput
có chức năng tương tự như flash
, sẽ flash session các input từ request. Chính vì thế bạn có thể thực hiện lọc các flash input trong method withInput
.
Nếu bạn muốn redirect một đường dẫn bất kì thì có thể sử dụng method redirect
để thay thế cho back
. Method redirect
sẽ nhận tham số là URI mà bạn muốn chuyến hướng đến.
c. Lấy old input (Retrieving old input)
Đế lấy old input từ request trước, sử dụng method old
có trong Illuminate\Http\Request
. Phương thức này sẽ lấy flash session đã lưu trữ ở request trước với tham số nhận vào là tên input.
Ngoài ra, Laravel còn cung cấp cho ta global helper function old
. Với nó, ta có thể lấy bất kỳ flash input nào ngay cả trong Blade template. Nếu flash input không tồn tại, nó sẽ trả về giá trị null
.
Nói nãy giờ mình nghĩ ta nên thực hành một chút. Chúng ta sẽ sử dụng các route và controller đã đăng ký ở trước. Tại blade view form
, mình có HTML form như sau:
Mục đích mình muốn là sau khi nhấn nút "Login" thì sẽ quay trở lại form này và truyền flash input chỉ cho input "username". Chính vì thế mình chỉ khai báo old
ở trong input "username" thôi.
Rồi bây giờ chúng ta qua code xử lý logic trong controller FormController
tại hàm post
.
Như bạn thấy, mình sử dụng method back
để trở về lại trang form, tiếp theo là setup flash input với method withInput
, cuối cùng là lọc flash input mà mình muốn. Các bạn thử điền username và password, sau đó nhấn nút "Login", và đây là kết quả:
Input data của "username" đã được giữ lại sau khi trở về trang form, nếu các bạn refresh trang form lần nữa, thì các flash input sẽ biến mất.
8. Cookie
Tất cả cookie được tạo bởi framework đã mã hóa và đăng ký bằng các mã chứng thực, chính vì vậy nó sẽ được coi là không hợp lệ nếu người dùng cố tình thay đổi.
a. Lấy cookie từ request (Retrieving cookie from request)
Để nhận một giá trị cookie từ request, bạn có thể sử dụng method cookie
trong lớp khởi tạo Illuminate\Http\Request
.
Ngoài ra, bạn có thể sử dụng Cookie
facade để thay thế.
b. Đính kèm cookie đến response (Attaching cookie to response)
Bạn có thể đính kèm mộ cookie đến object Illuminate\Http\Response
bằng cách sử dụng method cookie
. Bạn nên truyền đầy đủ tham số tên, giá trị cookie và thời gian tồn tại của cookie (tính theo phút). Nếu bạn bỏ qua tham số thời gian, Laravel sẽ coi cookie tồn tại như một session.
Method cookie
hoạt động tương tự hàm setcookie
mặc định của PHP. Chính vì vậy nó cũng có thể nhận một số tham số tùy chọn khác.
Ngoài ra bạn có thể sử dụng method queue
trong Cookie
facade. Nói một chút về "queue", nó có nghĩ đen là "xếp hàng". Hiểu một cách đơn giản, thì set cookie "queue" sẽ thực hiện cuối cùng khi đã hoàn tất cả xử lý khác trong request hiện tại. Để hiểu hơn thì chúng ta sẽ đi đến thử nghiệm.
Tại blade view form
, các bạn thay đổi nội dung như sau:
Mình đã inject Cookie
facade để có thể lấy cookie tại blade template. Ngoài ra bên dưới còn có form đển thực thi set cookie thông qua method post
trong FormController
.
Bây giờ các bạn thử đoán xem khi mình click vào nút "Set cookie" thì có hiển thị cookie với tên name
tại route /post
không? Đáp án là "Không", như mình đã nói ở trên, cookie name
được thiết lập bằng phương thức "queue", chính vì vậy nó sẽ thực hiện sau cùng, sau cả lệnh echo
cookie. Nhưng nếu bạn đi đến đường dẫn http:/localhost:8000 thì tại blade view form
, sẽ render cookie mà ta vừa set.
c. Generating cookie instances
Mục này mình không biết đặt tên như thế nào nên lấy theo Laravel Docs. Đại khái nếu bạn muốn set cookie chỉ khi cookie đó trả về cùng với response thì đăng ký cookie với method cookie
. Cách này rất giống với cách đăng ký ở trên nhưng chúng ta có thể chèn một tham số object thay vì các tham số riêng lẻ như trên.
V. File
1. Lấy file được upload (Retrieving uploaded file)
Bạn có thể truy cập tới các file được upload từ lớp Illuminate\Http\Request
thông qua method file
, hoặc theo cú pháp thuộc tính (nếu input đó có type là file
). Phương thức này sẽ trả về lớp khởi tạo Illuminate\Http\UploadedFile
, lớp này sẽ kế thừa class SplFileInfo
của PHP, cung cấp một số phương thức để tương tác với file.
Để bắt đầu thử nghiệm các phương thức bên dưới, ta cần build một HTML form đã. Mình sẽ lấy blade view form
và controller FormController
ở trên. Tại blade view form
, các bạn xây dựng form HTML như thế này:
Nên nhớ phải thêm enctype="multipart/form-data"
để có thể gửi input data file.
Tiếp theo là code xử lý logic tại post
của FormController
. Đầu tiên ta hãy thử dump xem dữ liệu ta nhận được từ request là gì.
Rồi nạp server và thử đính kèm một tệp ảnh rồi nhấn "Upload" xem, kết quả bạn sẽ nhận được sẽ là:
Như các bạn thấy, ngoài _token
ra, chúng ta còn nhận được avatar
gán với object UploadedFile
giống như ta đã đề cập ở trên.
Bạn có thể sử dụng multiple upload file, thay vì sẽ chứa một object UploadedFile
thì nó sẽ là mảng chứa các object UploadedFile
.
a. Kiểm tra một file có tồn tại trong request (Determining if a file is present on the request)
Bạn có thể sử dụng method hasFile
để kiểm tra sự tồn tại của một file trong request hiện tại.
b. Xác thực upload thành công (Validation successful upload)
Ngoài việc xác định file có tồn tại không, bạn có thể xác thực có lỗi gì trong quá trình upload hay không thông qua method isValid
, nếu không có vấn đề gì, sẽ trả về true
.
Ngoài ra để xem lỗi của file trong quá trình upload, bạn có thể dùng method getErrorMessage
từ Illuminate\Http\UploadedFile
.
Lưu ý: Mình có test hàm này, nhưng dù không có lỗi nó vẫn trả về một chuỗi với nội dung "The file "image.jpg" was not uploaded due to an unknown error.". Vì vậy, dù có gặp lỗi này cũng không quá lo lắng. Nếu không chắc, bạn có thể xem method
getErrorMessage
tại đây. Trong đó có liệt kê các lỗi mà Laravel có thể khai báo, đồng thời bạn cũng có thể sẽ hiểu lý do vì sao upload thành công như nó vẫn trả về một câu thông báo lỗi.
Nếu muốn chính xác trong quá trình xác thực, bạn nên sử dụng method getError
để trả về mã lỗi trong quá trình upload, nếu trả về 0
thì không có lỗi.
c. Lấy một số thuộc tính của file (Retrieving some properties of file)
Dưới đây mình sẽ liệt kệ các method khai khác các thông tin/thuộc tính của file có trong Illuminate\Http\UploadedFile
.
Phương thức | Công dụng |
getClientOriginalName | Trả về tên đầy đủ của file. Ví dụ: image.jpg |
getClientOriginalExtension | Trả về đuôi mở rộng của file. Ví dụ: jpg |
getClientMimeType | Trả về MIME của file. Ví dụ: image/jpeg |
guessClientExtension | Dự đoán đuôi mở rộng dựa trên MIME của file |
getClientSize | Trả về dung lượng của file (byte) |
getMaxFilesize | Trả về dung lượng tối đa trong một lần upload tại cấu hình |
2. Lưu trữ file upload (Storing uploaded file)
Laravel cung cấp cho chúng ta một số disk lưu trữ các file upload như local
, ftp
, s3
..., các cấu hình đó được thực hiện tại config/filesystem.php
. Nhưng tại bài này mình chỉ giới thiệu về disk local
thôi, các disk khác chúng ta sẽ tìm hiểu ở những tập sau.
Với disk local
, các file khi upload sẽ được lưu trữ ngay trên hệ thống tại thư mục storage/app
. Nếu bạn không thích thư mục mặc định này, bạn có thể thay đổi trong file cấu hình.
Để lưu trữ một file đã upload bất kỳ, ta sử dụng method store
.
Method store
này sẽ nhận hai tham số:
Tham số thứ nhất là path chứa file, tức là
storage/app/{path}
. Nếu path chưa tồn tại, Laravel sẽ tự khởi tạo thư mục cho chúng ta.Tham số thứ hai (tùy chọn) sẽ là tên disk lưu trữ file, nếu không khai báo framework sẽ tự hiểu ta đang sử dụng disk
local
.
Sau khi thực thi method store
này, nếu kiểm tra source bạn sẽ thấy các file lưu trữ đã bị đổi tên theo mã token nào đó.
Nếu bạn không muốn như thế, bạn có thể sử dụng method storeAs
thay thế cho store
để upload file với tên theo ý muốn.
Lưu ý: Hai method
store
vàstoreAs
sẽ trả về path file vừa lữu trữ.
VI. Cấu hình proxy tin cậy (Configuring trusted proxy)
Khi chạy ứng dụng với TLS/SSL, đôi khi ứng dụng sẽ không tạo đường dẫn HTTPS. Thông thường điều này là do ứng dụng của bạn đang được chuyển tiếp lưu lượng truy cập từ bộ cân bằng tải của bạn trên cổng 80 và không biết nó sẽ tạo ra các liên kết an toàn.
Để giải quyết vấn đề này, bạn có thể sử dụng middleware có trong Laravel, cho phép bạn nhanh chóng tùy chỉnh các bộ cân bằng tải hoặc proxy tin cậy. Các proxy tin cậy sẽ được liệt kê ở mảng $proxies
trong middleware TrustProxies
.
Lưu ý: Nếu bạn đang sử dụng AWS,
$header
sẽ nhận giá trị củaRequest::HEADER_X_FORWARDED_AWS_ELB
.
Nếu bạn đang sử dụng Amazon AWS hoặc nhà cung cấp cân khác, bạn có thể không biết địa chỉ IP của bộ cân bằng thực tế của mình. Trong trường hợp này, bạn có thể sử dụng *
để tin tưởng tất cả các proxy:
Cảm ơn các bạn đã quan tâm theo dõi. Cùng đồng hành với mình qua những tập tiếp theo tại series "Hành trình chinh phục Laravel Framework" nhé! Chúc may mắn và hẹn gặp lại.
Last updated