跨域問題的產生: 因為瀏覽器有同源策略,只有在同功能變數名稱,同埠,同協議的情況下才可以進行數據交互;有的時候,例如:在公司開發項目的時候,前端開發的伺服器可能和後端伺服器不是同一個,因為可能是通過gulp、webpack搭建的開發伺服器,就需要解決跨域問題,再例如,在大公司數據伺服器不只有一個,所以跨域 ...
跨域問題的產生:
因為瀏覽器有同源策略,只有在同功能變數名稱,同埠,同協議的情況下才可以進行數據交互;有的時候,例如:在公司開發項目的時候,前端開發的伺服器可能和後端伺服器不是同一個,因為可能是通過gulp、webpack搭建的開發伺服器,就需要解決跨域問題,再例如,在大公司數據伺服器不只有一個,所以跨域問題也必然存在
一、jsonp解決跨域請求
jsonp是一種前後端結合的跨域方式,原理就是通過script標簽的src屬性來進行數據請求,src不受同源策略的影響,故而能請求到數據,需要註意的是,數據處理需要通過回調函數來進行,而本質上,我們把回調函數的名字告訴後端,後端將數據放入到回調函數里,所以說需要告知後端,回調函數是什麼,這也就是為什麼說jsonp是前後端結合的方式。
註意:一個script只能請求一次,多次請求應該去動態的創建script,回調函數也只能使用一次,所以也需要動態創建 ,使用完成後移除,避免污染全局空間
缺點:jsonp只能get請求
1、nodejs代碼,配置路由(使用express模塊)
//後端的任務,就是把數據放到前端的那個函數里並給它執行一下
//直接返回這個操作的js字元串,因為這個字元串會被script當成js代碼來運行
app.get('/data', function(req, res) {
//前端回調函數的名字
let fn = req.query['callback'];
//註意,在content 後拼接一個空字元串,將獲取的數據轉義正常輸出,否則有時候讀取的數據格式為buffer數據類型
var content = fs.readFileSync('./datas/data.json') + '';
//返回給前端函數數據
res.send(fn + '(' + content + ')');
});
2、js代碼,返回數據(函數中用到的是es6解構賦值參數)
Jsonp({
url: "http://localhost:3000/data",
success(results) {
console.log(results)
}
})
function Jsonp({ url, success }) {
//動態創建script標簽
let $script = $("")
//隨機函數名字
var random_name = 'random_fn_' + Date.now()
//創建的隨機全局函數
window[random_name] = function(data) {
success(data)
//處理完數據之後,將script刪掉,函數delete掉
$script.remove()
delete window[random_name]
}
$script[0].src = url + '?callback=' + random_name
$("body").append($script)
}
二、cors解決跨域請求
cors純後端的解決方式,每次請求都會有一個origin信息被後端捕捉,後端可以通過設置對這個origin的域允許訪問來解決跨域問題
1、nodejs代碼
app.get("/data_cors", (req, res) => {
//此次請求的源信息
var reqOrigin = req.header("origin");
//如果源信息存在,且源是運行訪問的
if (reqOrigin != undefined && reqOrigin.indexOf("http://localhost:9000") > -1) {
//設置允許 http://localhost:3000 這個域響應
res.header("Access-Control-Allow-Origin", "http://localhost:9000");
//允許這個域訪問
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
//允許的請求方法
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
}
res.send('123')
})
2、js代碼獲取返回的數據
$.ajax({
url:"http://localhost:3000/data_cors",
success(results){
console.log(results)
}
})
三、服務端代理proxy解決跨域請求
因為伺服器間的數據交互沒有跨域限制,所以我們可以通過一個中間代理伺服器來請求目標伺服器的數據,也就是開發伺服器發送請求到代理伺服器,代理伺服器再請求目標伺服器,將數據返回給開發伺服器
1、nodejs代碼
//目標伺服器介面 3000:
app.get("/data_proxy",(req,res)=>{
//此次請求的源信息
res.send('proxy')
})
2、代理伺服器1234:
app.get("/to3000", (req, res) => {
//代理伺服器1234對9000做跨域處理
var reqOrigin = req.header("origin");
//如果源信息存在,且源是運行訪問的
if (reqOrigin != undefined && reqOrigin.indexOf("http://localhost:9000") > -1) {
//設置允許 http://localhost:3000 這個域響應
res.header("Access-Control-Allow-Origin", "http://localhost:9000");
//允許這個域訪問
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
//允許的請求方法
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
}
//獲取到9000真正要調用的3000目標伺服器的介面
var url = req.query['url']
let _res = res
//代理伺服器1234像目標伺服器3000發送請求(沒有跨域限制)
http.get(url, (res) => {
let result = ''
res.on("data", (chunk) => {
result += chunk
})
res.on("end", () => {
console.log(result)
//代理伺服器1234將請求到的目標伺服器3000的數據返回給開發伺服器9000
_res.send(result)
})
})
})
app.listen(1234);
3、js代碼,開發伺服器9000:
//當前伺服器9000向代理伺服器1234發送請求
$.ajax({
url: "http://localhost:1234/to3000",
data: {
url: "http://localhost:3000/data_proxy"
},
success(results) {
console.log(results)
}
})