程序開發人員,不拘泥於語言與技術,目前主要從事PHP和前端開發,使用Laravel和VueJs,App端使用Apicloud混合式開發。合適和夠用是最完美的追求。javascript
我的網站:http://www.linganmin.cnphp
最近剛寫了一個手機在線播放的H5電影站:http://www.ifilm.ltd前端
laravel-cors
使用的laravel-cors
的做用是用於解決瀏覽器跨域的問題java
安裝jquery
在終端執行安裝命令以下:laravel
composer require barryvdh/laravel-cors
添加服務提供商git
在Laravel配置文件app.php
的providers
數組中添加以下配置:github
Barryvdh\Cors\ServiceProvider::class,
發佈配置文件web
執行在終端執行發佈配置文件命令以下:ajax
php artisan vendor:publish --provider="Barryvdh\Cors\ServiceProvider"
執行後會在laravel目錄下的config目錄中新增cors.php
配置文件,以下圖
至此laravel-Cors
安裝完成。
什麼是跨域
跨域是指從一個域名的網頁去請求另外一個域名的資源。好比從www.baidu.com 頁面去請求 www.google.com 的資源。跨域的嚴格一點的定義是:只要 協議,域名,端口有任何一個的不一樣,就被看成是跨域
爲何瀏覽器要限制跨域訪問
緣由就是安全問題:若是一個網頁能夠隨意地訪問另一個網站的資源,那麼就有可能在客戶徹底不知情的狀況下出現安全問題。
爲何要跨域
既然有安全問題,那爲何又要跨域呢? 有時公司內部有多個不一樣的子域,好比一個是b.a.com ,而應用是放在c.a.com , 這時想從b.a.com去訪問 location.company.com 的資源就屬於跨域。
如何解決跨域問題
跨域訪問須要用到兩樣東東,一個是JSON,一種基於文本的傳輸協議;一種是JSONP,一羣碼農想出來的跨域解決方案。
服務端須要作的
服務端要檢查訪問的請求參數,若是沒有callback,則能夠按照以前的流程走;若是帶着callback參數,則須要將返回的結果包裝在callback裏面。
客戶端(瀏覽器)須要作的
客戶端能夠多種方式能夠實現JSONP的調用
larave-cors作了什麼
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。
它容許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。laravel-cors
官方介紹入下:
The
laravel-cors
package allows you to send Cross-Origin Resource Sharing headers with ACL-style per-url configuration.
也就是說,laravel-cors
是在服務端容許了全部帶有跨域資源請求的header,並當成正常請求處理,從服務端解決了跨域資源共享的問題。
關於更多的laravel-cors
使用配置,請移步 larave-cors官方GitHub倉庫
要說遇到的坑,首先要介紹一下laravel處理的路由模式,官方文檔這樣說:
全部的 Laravel 路由都在 routes 目錄中的路由文件中定義,這些文件都由框架自動加載。 routes/web.php 文件中定義你的 web 頁面路由。這些路由都會應用 web 中間件組,其提供了諸如 Session 和 CSRF 保護等特性。定義在 routes/api.php 中的路由都是無狀態的,而且會應用 api 中間件組。
能夠獲得的信息以下:
laravel中有兩個默認路由配置,一個是routes目錄下的web.php
,一個是routes目錄下的api.php
;
web.php
中定義的路由默認使用了Session 和 CSRF 保護等特性,因此能夠直接使用會話技術,也就是正常的頁面請求處理是默認走的web.php
中定義的路由或路由組
api.php
的全部路由都是無狀態的,而且沒有使用Session 和 CSRF 保護的特性保護,因此裏面定義的路由更適合爲app提供接口,laravel默認當用戶的請求路由前綴爲api
時,laravel自動去調用api.php
中所定義的路由或路由組。這是由於,在laravel的路由服務提供者
中配置了路由前綴爲api
,下圖爲路由服務提供者
所在目錄路徑
下圖爲無狀態路由組api.php
的配置:
因此當url以相似www.xxx.com/api/route
的請求時會自動調用api.php
路由組所定義的路由
上面說到api.php
中定義的路由爲無狀態的,並且api.php
中更適合提供api接口,因此爲了解決跨域咱們安裝了laravel-cors
,而僅僅安裝仍是不夠的,咱們須要在會產生跨域的路由組中使用laravel-cors
爲咱們提供的中間件,因此咱們能夠這樣使用laravel-cors
// 給須要跨域的路由增長cors中間件 Route::group(['middleware' => 'cors'], function(Router $router){ $router->get('api', 'ApiController@index'); });
當咱們整個api.php
路由組所有須要跨域時,咱們還能夠在laravel框架的appHttpKernel.php文件中配置api.php
路由組中增長cors
中間件,以下:
/** * The application's route middleware groups. * * @var array */ protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ 'throttle:60,1', 'bindings', 'cors'// install laravel-cros 增長cors中間件,解決跨域問題 ], ];
注意,若是安裝
laravel-cors
以後仍是出現跨域問題,必定必定不要忘記檢查一下是否增長了cors
中間件
具體的表單驗證請查看官方給出的文檔(laravel的中文文檔像laravel框架同樣優雅),附上 laravel表單驗證中文文檔地址
下面很重要
想說的是當ajax請求時,若是表單驗證失敗,則會產生一次重定向,而後傳回一個 HTTP 響應,其中包含了 422 狀態碼和驗證錯誤的 JSON 數據,可是咱們在客戶端看到的卻有多是一個關於ajax跨域的錯誤,這是由於咱們在使用jquery或者其餘JavaScript包的ajax請求方法請求時,沒有指定返回的數據類型爲json,而laravel的錯誤處理默認解析爲普通web請求,laravel表單驗證規則上面也說到了,當驗證失敗,會產生一次重定向,而咱們會看到的倒是一個關於跨域的報錯,下面是一個例子:
在api.php
路由組中定義了登陸路由以下
// 登陸路由,使用依賴注入請求驗證 Route::post('login', function (\App\Http\Requests\LoginRequest $request) { // 獲取到經過請求的兩個字段 $checkInfo = \Illuminate\Support\Facades\Input::only('mobile', 'password'); try { // 爲該用戶驗證,驗證經過則生成token,失敗返回錯誤提示 if (!$token = JWTAuth::attempt($checkInfo)) { return Response::json(['error' => '帳號或密碼錯誤'], 401); } return [ 'user'=>JWTAuth::toUser($token), 'token'=>$token ]; } catch (\Tymon\JWTAuth\Exceptions\JWTException $e) { // 返回捕獲的異常 return Response::json($e->getMessage(), 500); } });
在api.php
路由組中使用的表單驗證類\App\Http\Requests\LoginRequest
定義以下
<?php namespace App\Http\Requests; use App\User; use Illuminate\Foundation\Http\FormRequest; class LoginRequest extends FormRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { // 調用了模型靜態屬性定義好的驗證規則 return User::$rules; } public function messages() { // 調用了模型靜態屬性定義好的驗證規則提示 return User::$messages; } }
在用戶模型中定義的驗證規則和驗證提示以下
public static $rules = [ 'mobile'=>'required', 'password'=>'required' ]; public static $messages = [ 'mobile.required'=>'手機號不能爲空', 'password.required'=>'密碼不能爲空' ];
使用jquery的post請求發送ajax請求
$.post('http://192.168.1.6:9999/api/login',{},function(data){ console.log(data) });
由於該post請求並未傳遞任何參數,因此驗證多是未經過,但咱們看到的確實一個關於跨域失敗的報錯,以下圖
產生這個報錯是由於咱們在發送post請求時沒有指按期望返回的數據類型,而laravel框架就將其判斷爲一個普通的web請求,並返回302跳轉到發送請求的頁面,在這個過程當中產生了跨域,以下圖
因此當咱們在發送ajax請求時,指按期望的返回類型時,就能夠看到laravel爲咱們返回的422的驗證失敗的報錯了,代碼和效果以下圖:
對應報錯返回的json數據以下圖:
因此,在請求laravel的接口時必定要指按期望的返回數據類型