跨域解决方案
协议、域名、端口号,只要有一个不一样都是跨域请求
1、跨域存在的原因
+ 服务器分开部署:WEB服务器、数据服务器、图片服务器…(分开部署,有助于服务器资源的合理利用)
+ 本地开发:本地预览项目 调取 测试服务器上的数据
+ 调取第三方平台API接口
2、跨域主要解决方案
只对一下三种做了讲解
+ JSONP
+ CORS
+ Proxy
(1)JSONP
JSONP:利用SCRIPT标签不存在域的限制实现跨域请求
(1)弊端:
(A)只能是GET请求
(B)不安全,只要服务器支持,谁都可以调用)
(2)callback必须是一个全局上下文中的函数(防止不是全局的函数,需要把这个函数放置到全局上)
// 前端代码
function request(url = "", callback) {
let script;
// 把传递的回调函数挂载到全局上
let name = `jsonp${new Date().getTime()}`
window[name] = (data) => {
// data 从服务器获取到了结果
document.body.removeChild(script);
delete window[name];
callback && callback(data);
}
// 处理URL
url += `${url.includes('?') ? '&' : '?'}callback=${name}`
// 发送请求
script = document.createElement('script')
script.src = url
document.body.appendChild(script);
}
request('http://127.0.0.1:8099/list', result => {
console.log(result);
});
// 服务器代码
let http = require('http')
let fs = require('fs')
let url = require('url')
// 起服务
let server = http.createServer((req, res)=>{
let { pathname, query } = url.parse(req.url)
let callback = query.split('=')[1]
// 请求
if(pathname == '/list'){
// 准备返回的数据
let result = {
code: 0,
data: [10, 20]
};
let str = `${callback}(${JSON.stringify(result)})`;
res.end(str);
}
})
server.listen(8099,()=>{
console.log('8099接口请求成功')
})
(2)CORS
客户端正常请求,服务端设置可请求的 源
'Access-Control-Allow-Origin':
(1)*:允许所有源
不安全;
不能携带资源凭证;
(2)设置单一源
安全;
可以携带资源凭证( 只能是单一一个源);
(3)动态设置多个源
设置一个白名单,客户端请求的源在白名单中,我们把Allow-Origin动态设置为当前这个源
// 前端
get.onclick = function () {
fetch('http://127.0.0.1:8099/list', {
credentials: 'include',
}).then(res => res.text()).then(data => {
console.log(data)
})
}
// 后端
let http = require('http')
let fs = require('fs')
let url = require('url')
//白名单
let allowOrigin = [
'http://127.0.0.1:8099',
'http://127.0.0.1:5500',
'http://127.0.0.1:5502'
]
let server = http.createServer((req, res) => {
// 设置允许源
// * : 允许所有源(不安全/不能携带资源凭证)
// 设置单一源(安全/也可以携带资源凭证/只能是单一一个源)
// 可以动态设置多个源:每一次请求都会走这个中间件,我们首先设置一个白名单,如果当前客户端请求的源在白名单中,我们把Allow-Origin动态设置为当前这个源
// 前端请求域名
if (allowOrigin.includes(req.headers.origin)) {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
res.setHeader('access-control-allow-credentials', true)
}
// 后端设置cookie
res.setHeader('Set-Cookie', ['a=123;SameSite=Secure'])
let { pathname } = url.parse(req.url)
// 试探请求:在CORS跨域请求中,首先浏览器会自己发送一个试探请求,验证是否可以和服务器跨域通信,服务器返回200,则浏览器继续发送真实的请求
req.method === 'OPTIONS' ? res.send('CURRENT SERVICES SUPPORT CROSS DOMAIN REQUESTS!') : next();
// 请求
if (pathname == '/list') {
// 准备返回的数据
let result = {
code: 0,
data: [10, 20]
};
res.end(JSON.stringify(result));
}
})
server.listen(8099, () => {
console.log('8099接口请求成功')
})
(3)Proxy
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'production',
entry: './src/main.js',
output: {
filename: 'main.[hash].min.js',
path: path.resolve(__dirname, 'build')
},
devServer: {
port: '3000',
compress: true,
open: true,
hot: true,
proxy: {
'/': {
target: 'http://127.0.0.1:3001',
changeOrigin: true
}
}
},
// 配置WEBPACK的插件
plugins: [
new HtmlWebpackPlugin({
template: `./public/index.html`,
filename: `index.html`
})
]
}