【发布时间】:2016-05-08 16:02:53
【问题描述】:
我在 Laravel 5.2 中遇到了 AJAX POST 请求的问题。我在我的 AJAX 请求中传递了一个有效的 CSRF 令牌。
使用Laravel Collective HTML package 表单标签打开和关闭表单,它会自动添加带有 CSRF 令牌的隐藏 _token 输入。呈现的 HTML:
<form method="POST" action="http://www.example.com/admin/products/search" accept-charset="UTF-8" id="product-search-form">
<input name="_token" type="hidden" value="mOaBxU1sVUsRX1KkuAeVhSDSxj0LKT8DDxl9USQc">
<div>
<label for="keywords" class="required">Keywords</label>
<input id="keywords" placeholder="Enter keywords" name="keywords" type="text">
</div>
<div>
<label for="category" class="required">Category</label>
<select id="category" name="category">
<option selected="selected" value="">Choose a category...</option>
<option value="category-1">Category 1</option>
<option value="category-2">Category 2</option>
<option value="category-3">Category 3</option>
</select>
</div>
<div>
<button id="search-product-submit" type="submit">Search</button>
</div>
</form>
使用 Fetch API 和 FormData 做 AJAX 请求:
function $(id) {
return document.getElementById(id);
}
var searchProductSubmitButton = $("search-product-submit");
function fetchStatus(response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response);
} else {
return Promise.reject(new Error(response.statusText));
}
}
function fetchJson(response) {
return response.json();
}
function searchProducts(evt){
var keywords = $("keywords").value,
categorySelect = $("category"),
category = categorySelect.options[categorySelect.selectedIndex].value,
csrfToken = document.getElementsByTagName("meta")["csrf-token"].getAttribute("content"),
productSearchForm = $("product-search-form"),
formData = new FormData(productSearchForm);
evt.preventDefault();
if(keywords !== "" && category !== ""){
fetch("/admin/products/search", {
method: "POST",
body: formData,
headers: {
"X-CSRF-TOKEN": csrfToken
}
})
.then(fetchStatus)
.then(fetchJson)
.then(function(products) {
console.log("The operation was a complete success");
}).catch(function(error) {
console.log("Request failed", error);
});
}
}
searchProductSubmitButton.addEventListener("click", searchProducts, false);
searchProductSubmitButton.addEventListener("keypress", searchProducts, false);
CSRF 令牌和表单数据在请求负载中:
------WebKitFormBoundaryQFECPn7xpptqi076
Content-Disposition: form-data; name="_token"
mOaBxU1sVUsRX1KkuAeVhSDSxj0LKT8DDxl9USQc
------WebKitFormBoundaryQFECPn7xpptqi076
Content-Disposition: form-data; name="keywords"
dsafafa
------WebKitFormBoundaryQFECPn7xpptqi076
Content-Disposition: form-data; name="category"
DVD
------WebKitFormBoundaryQFECPn7xpptqi076--
请求负载中的 _token 输入和 x-csrf-token 标头与查看源代码中看到的令牌相同。
Route 正在使用 Web 中间件:
Route::group(['prefix' => 'admin', 'middleware' => 'web'], function () {
Route::post('products/search', [ // == "admin/products/search" with prefix
'as' => 'products.search',
'uses' => 'ProductsController@search'
]);
});
控制器:
public function search(SearchRequest $request){
Log::info('keywords: ' . $request->keywords);
Log::info('category: ' . $request->category);
return response()->json([
'keywords' => $request->keywords,
'category' => $request->category
], 200);
}
【问题讨论】:
-
在收到令牌和提交令牌之间是否对您的应用程序有任何请求?
-
不,我在本地开发环境中,只在一个浏览器选项卡中打开网站。
-
你确定你没有生成两次吗?一次用于表单元素,一次用于元标记?
-
元标签和隐藏表单域是一样的。
标签: javascript ajax forms laravel