用原生js实现:
//简单实现jsonp
function jsonpCallback(result) {
//alert(result);
for (var i in result) {
console.log(i + ":" + result[i]); //循环输出result的元素
}
}
var JSONP = document.createElement("script");
JSONP.type = "text/javascript";
JSONP.src = "http://180.167.10.100/update/index.php?callback=jsonpCallback";
document.getElementsByTagName("head")[0].appendChild(JSONP);
//封装好的jsonp
var jsonp = function (url, data, callback) {
// 1.将传入的data数据转化为url字符串形式
// {id:1,name:'zhangsan'} => id=1&name=zhangsan
var dataString = url.indexof('?') == -1 ? '?' : '&';
for (var key in data) {
dataString += key + '=' + data[key] + '&';
};
// 2 处理url中的回调函数
// cbFuncName回调函数的名字 :my_json_cb_名字的前缀 + 随机数(把小数点去掉)
var cbFuncName = 'my_json_cb_' + Math.random().toString().replace('.', '');
dataString += 'callback=' + cbFuncName;
// 3.创建一个script标签并插入到页面中
var scriptEle = document.createElement('script');
scriptEle.src = url + dataString;
// 4.挂载回调函数
window[cbFuncName] = function (data) {
callback(data);
// 处理完回调函数的数据之后,删除jsonp的script标签
document.body.removeChild(scriptEle);
}
// 5.append到页面中
document.body.appendChild(scriptEle);
}
// 因为jsonp是一个私有函数外部不能调用,所有jsonp函数作文window对象的一个方法,供外部调用
window.$jsonp = jsonp;
用jq实现jsonp
$.ajax({
type: "get",
async: false,
url: "http://test.com/json_data.php",
dataType: "jsonp",
jsonp: "callback", //传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback: "mycall", //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名
success: function (data) {
console.log(data);
},
error: function () {
alert('fail');
}
});
客户端正常发出ajax请求,只需要服务端配置即可,不同的后台语言写法不同,但是配置项是一样的,需要配置以下几个值。
(1)Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
(2)Access-Control-Request-Method
该字段用来列出浏览器的CORS请求会用到哪些HTTP方法
(3)Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。
Access-Control-Allow-Credentials: true
另一方面,开发者必须在AJAX请求中打开withCredentials属性。
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
(4)Access-Control-Expose-Headers
该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers面指定。
//例如
header("Access-Control-Allow-Origin: * ");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE");
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type,
Accept, Connection, User-Agent, Cookie,token');
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Node.js配合node-http-proxy解决本地开发ajax跨域问题
npm init
npm install http-proxy --save-dev
var PORT = 8088;
var APIServer = 'https://me.csdn.net'; // 后台服务器地址http://172.16.0.111 http://cochat.cn
var APIPrefix = '/api/'; // 反向代理api前缀
var http = require('http');
var url = require('url');
var fs = require('fs');
var mine = require('./mine').types;
var path = require('path');
var httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({
target: APIServer, //接口地址
proxyTimeout: 5 * 60 * 1000,
// 下面的设置用于https
// ssl: {
// key: fs.readFileSync('server_decrypt.key', 'utf8'),
// cert: fs.readFileSync('server.crt', 'utf8')
// },
// secure: false
});
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'content-type': 'text/plain'
});
console.log(err);
res.end('Something went wrong. And we are reporting a custom error message.');
});
var server = http.createServer(function (request, response) {
var pathname = url.parse(request.url).pathname;
var query = url.parse(request.url).query;
//var realPath = path.join("main-pages", pathname); // 指定根目录
//判断如果是接口访问,则通过proxy转发
if (pathname.indexOf(APIPrefix) > 0) {
request.url = '/' + pathname.substr(APIPrefix.length) + (query ? '?' + query : '');
proxy.web(request, response);
return;
}
if (path.extname(pathname) == "") {
pathname += "/";
}
if (pathname.charAt(pathname.length - 1) == "/") {
pathname += "index.html";
}
console.log(pathname);
var realPath = path.join("./", pathname);
console.log(realPath);
fs.exists(realPath, function (exists) {
if (!exists) {
response.writeHead(404, {
'Content-Type': 'text/plain'
});
response.write("This request URL " + pathname + " was not found on this server.");
response.end();
} else {
fs.readFile(realPath, "binary", function (err, file) {
if (err) {
response.writeHead(500, {
'Content-Type': 'text/plain'
});
response.end(err);
} else {
var ext = path.extname(realPath);
ext = ext ? ext.slice(1) : 'unknown';
var contentType = mine[ext] || "text/plain";
response.writeHead(200, {
'Content-Type': contentType
});
response.write(file, "binary");
response.end();
}
});
}
});
});
server.listen(PORT);
console.log("Server runing at port: " + PORT + ".");
exports.types = {
"css": "text/css",
"gif": "image/gif",
"html": "text/html",
"ico": "image/x-icon",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"js": "text/javascript",
"json": "application/json",
"pdf": "application/pdf",
"png": "image/png",
"svg": "image/svg+xml",
"swf": "application/x-shockwave-flash",
"tiff": "image/tiff",
"txt": "text/plain",
"wav": "audio/x-wav",
"wma": "audio/x-ms-wma",
"wmv": "video/x-ms-wmv",
"xml": "text/xml",
"woff": "application/x-woff",
"woff2": "application/x-woff2",
"tff": "application/x-font-truetype",
"otf": "application/x-font-opentype",
"eot": "application/vnd.ms-fontobject"
};
启动nodejs服务
启动cmd,定位到项目目录,运行
node proxy.js
访问:
http://localhost:3000/index.html
可以看到项目中调用的http://localhost:3000/… 都会从http://192.168.10.38:8180/… 获取数据,然后转发到本地。
这样就不存在跨域了。