序
虽然angularjs自带http请求,但是当它的后台为php时,我们往往拿不到想要的数据(相同的请求用jQuery能正确返回结果)。其实这是因为angularjs默认的请求方式不适合php接收而已。因此我们需要修改或者使用其他的请求方式来实现与后台的交互。
$http默认请求头信息
$http服务将会给所有请求自动创建HTTP头。这个默认设置能完全的通过访问$httpProvider.defaults.headers配置对象配置。目前包含默:
$httpProvider.defaults.headers.common
//-- Accept:application/json,text/plain
$httpProvider.defaults.headers.post
//-- Content-Type:application/json
$httpProvider.defaults.headers.put
//-- Content-Type:application/json
解决方法
以下案例均通过wampserver环境下的php后台请求测试,如果非此类环境有可能拿不到想要的结果,请自行封装其他方法解决。
以下案例的实现均需要有正常的php开发环境来支持,假如我们有这样一个ajax.php文件:
<?php
header('Content-type:text/html;charset=utf-8');
if ($_GET) {
$msg = ['name' => $_GET['name'], 'type' => '这是get请求'];
echo json_encode($msg);
exit();
}
if ($_POST) {
$msg = ['name' => $_POST['name'], 'type' => '这是post请求'];
echo json_encode($msg);
exit();
}
$msg = ['type' => '这是其他请求'];
echo json_encode($msg);
方法一:封装自定义httpService服务(推荐做法)
利用$httpParamSerializerJQLike和Content-Type设置来封装自定义服务,可以友好解决这个问题,而且它可以像jQuery那样发请求(注意自定义服务的调用方式,如果不明白什么是服务,可以参考angularjs service 自定义服务 或者 angularjs factory (工厂服务))。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>angularjs service</title>
<meta name="author" content="loushengyue">
</head>
<body>
<div ng-app="app" ng-controller="ctrl">
<h1>请按F12查看控制台的console面板</h1>
</div>
<script src="https://cdn.bootcss.com/angular.js/1.6.9/angular.min.js"></script>
<script>
angular.module('app', [])
.controller('ctrl', ['$scope', 'httpService', function ($scope, httpService) {
var option = {
type: 'post',
url: './ajax.php',
data: {
name: 'loushengyue'
}
};
httpService.request(option).then(function (res) {
console.log(res);
}, function (error) {
console.log(error);
})
}])
.service('httpService', ['$http', '$q', '$httpParamSerializerJQLike',
function ($http, $q, $httpParamSerializerJQLike) {
//$httpParamSerializerJQLike表示它可以像jquery那样序列化数据
this.request = function (option) {
if (!option || !option.url) {
throw new Error('option or option.url is undefind.');
}
var def = $q.defer(), _method,
_data = option.data ? option.data : {};
option.method = option.method ? option.method : (option.type ? option.type : 'get');
_method = angular.uppercase(option.method);
if (_method === 'GET' && !option.params) {
option.params = _data; //使get请求支持data传参
}
if (_method === 'POST') {
var _config = {
headers: {"Content-Type": "application/x-www-form-urlencoded"}
};
option.data = $httpParamSerializerJQLike(_data);
angular.merge(option, _config);//合并请求参数使post请求类似jquery一样
}
$http(option).then(function (res) {
def.resolve(res.data)
}, function (error) {
def.reject(error)
});
return def.promise;
};
return this;
}])
</script>
</body>
</html>
方法二: 修改$httpProvider配制
这是一种各大博客网友推荐的一种做法,它能够一次性配制所有的$http内置服务的post请求方式(不过这种配制是有漏洞的,它不支持复杂参数的传递)。
<div ng-app="app" ng-controller="ctrl">
<h1>请按F12查看控制台的console面板</h1>
<div>
<button ng-click="getRequest()">get request test</button>
<br>
<button ng-click="postRequest()">post request test</button>
</div>
</div>
<script src="https://cdn.bootcss.com/angular.js/1.6.9/angular.min.js"></script>
<script>
angular.module('app', [])
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.transformRequest = function (data) {
var arr = [];
angular.forEach(data, function (val, key) {
arr.push(encodeURIComponent(key) + '=' + encodeURIComponent(val));
});
return arr.join('&');
};
//通过下面这一行你能看到你$http的默认配置信息
console.log($httpProvider.defaults.headers);//请自行删除本行
$httpProvider.defaults.headers = {
post: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
}])
.controller('ctrl', ['$scope', '$http', function ($scope, $http) {
$scope.getRequest = function () {
$http({
method: 'get',//切记这里是method!!jQuery用的是type
url: './ajax.php?name=loushengyue&age=30'
//angularjs的get请求没有data传参,需要拼接url或者用params对象
}).then(function (res) {
console.log(res.data);
alert('get success')
})
};
$scope.postRequest = function () {
$http({
method: 'post', //切记这里是method!!jQuery用的是type
url: './ajax.php',
data: {
name: 'loushengyue',
age: 30,
sex: 'male'
}
}).then(function (res) {
console.log(res.data);
alert('post success');
})
};
}])
</script>
方法三:修改$http配置
<div ng-app="app" ng-controller="ctrl">
<h1>请按F12查看控制台的console面板</h1>
<div>
<button ng-click="getRequest()">get request test</button>
<br>
<button ng-click="postRequest()">post request test</button>
</div>
</div>
<script src="https://cdn.bootcss.com/angular.js/1.6.9/angular.min.js"></script>
<script>
angular.module('app', [])
.controller('ctrl', ['$scope', '$http', '$httpParamSerializerJQLike',
function ($scope, $http, $httpParamSerializerJQLike) {
$scope.getRequest = function () {
$http({
method: 'get',//切记这里是method!!jQuery用的是type
url: './ajax.php',
params: {
name: 'test',
age: 18
}
//angularjs的get请求没有data传参,需要拼接url或者用params对象
}).then(function (res) {
console.log(res.data);
alert('get success')
})
};
$scope.postRequest = function () {
$http({
method: 'post', //切记这里是method!!jQuery用的是type
url: './ajax.php',
data: $httpParamSerializerJQLike({
name: 'loushengyue',
age: 30,
sex: 'male'
}),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function (res) {
console.log(res.data);
alert('post success');
})
};
}])
</script>
$httpParamSerializerJQLike部分原码展示
function jQueryLikeParamSerializer(params) {
if (!params) return '';
var parts = [];
serialize(params, '', true);
return parts.join('&');
function serialize(toSerialize, prefix, topLevel) {
if (toSerialize === null || isUndefined(toSerialize)) return;
if (isArray(toSerialize)) {
forEach(toSerialize, function (value, index) {
serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
});
} else if (isObject(toSerialize) && !isDate(toSerialize)) {
forEachSorted(toSerialize, function (value, key) {
serialize(value, prefix +
(topLevel ? '' : '[') +
key +
(topLevel ? '' : ']'));
});
} else {
parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
}
}
}
function encodeUriQuery(val, pctEncodeSpaces) {
return encodeURIComponent(val).
replace(/%40/gi, '@').
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
replace(/%3B/gi, ';').
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
}
function serializeValue(v) {
if (isObject(v)) {
return isDate(v) ? v.toISOString() : toJson(v);
}
return v;
}