最近重构移动端的页面,完全实现了前后端分离。开发的时候,前端用
webpack-dev-server
服务器来部署,后端还是之前的php
后台。在进行ajax
请求的时候,发现出现跨域的问题,在网上找了一些解决方案:
1. 使用 jsonp 实现跨域请求
我们移动端是用zepto
来替代jquery
,实现jsonp
比较简单。$.ajax
方法将dataType
换成jsonp
,加个jsonpCallback
参数就ok了。
自己封装了一个方法,开发环境用jsonp
,正式环境用json
constant.js
export default{
ENVIRONMENT: 'development',
}
utils.js
import Constant from './constant';
export default {
//ajax请求,默认是get请求,开发环境通过jsonp实现跨域
request(params) {
const ajax_data_type = Constant.ENVIRONMENT == 'development' ? 'jsonp' : 'json';
const default_params = {
type: 'GET',
dataType: ajax_data_type
};
if (Constant.ENVIRONMENT == 'development') {
//加上时间戳和随机数保证jsonpCallback参数的唯一性
const callback_handler = "jsonpHandler_" + new Date().getTime() + Math.floor(Math.random() * 1000000);
params.jsonpCallback = callback_handler;
}
$.each(default_params, function (key, val) {
if (!params[key]) {
params[key] = val;
}
});
$.ajax(params);
}
};
然后需要请求api的时候,调用这个方法就可以了
const params = {
url: Constant.API_URL + '/board_list/getBoardLists',
success: (json_return_data) => {
if (json_return_data.succeed == true) {}
}
};
Tool.request(params);
接下来,后台返回的数据格式也需要改一下。这里加了个分支,如果是开发环境,用jsonp
须得到前台传过来的$callback
参数,将需要返回的数据包装成一个方法
private function ajax_return_msg_to_view($info , $succeed) {
ob_start();
$this->output->set_header('Content-Type: application/json; charset=utf-8');
$return_value = array(
'succeed' => $succeed ,
'message' => $info
);
echo json_encode($return_value);
$output = ob_get_contents();
ob_end_clean();
if ($this->isMobile && ENVIRONMENT == "development") {
$callback = $_GET["callback"];
echo $callback . "(" . $output . ")";
} else {
echo $output;
}
}
到这里get请求是没有问题的,可是post的话,这样做就只能呵呵了。也找到了一些跨域post的解决方法,但觉得继续深入下去,有点违背初衷了。为了一个开发环境,写这么多冗余的代码有必要吗,其实一开始就弄错了方向。
2. 配置 webpack-dev-server 的 proxy
webpack-dev-server
是可以配置 proxy 代理的,用来代理某些请求。如它文档中所述,对于同一域下的前后端分离项目是非常有用的。
所以,我们首先得在 webpack.config.js
中配置 devServer
的 host
值与后端 api 的域一致。比如:后端 api 的地址为 http://test.com:80
,我们可以配置为 http://test.com:8080
。
然后,配置 proxy
,设置要转发的请求。这里配置了两个转发请求:
-
/api
的请求使用pathRewrite
做了重写,比如我的移动端地址为:http://test.com:8080
,相当于把http://test.com:8080/api/getXXX
转发到了http://test.com:80/getXXX
-
/avatar
相当于把http://test.com:8080/avatar/a.jpg
转发到了http://test.com:80/avatar/a.jpg
,这样就可以访问服务器的图片了
devServer: {
proxy: {
'/api': {
target: 'http://test.com:80',
secure: false,
changeOrigin: true,
pathRewrite: {'^/api': ''}
},
'/avatar': {
target: 'http://test.com:80',
secure: false,
changeOrigin: true
}
}
},
package.json
"scripts": {
"dev": "webpack-dev-server -d --progress --colors --inline --hot --port 8080",
},
然后在请求的方法中,直接使用 json 就可以了。比如:
const url = '/navbar/getMobileNotifications';
$.get(url, (json_return_data)=> {
if (json_return_data.succeed == false) return;
const data = json_return_data.message;
this.loadNotificationList(data);
}, 'json');