注: 文章摘自 寫Bug - 思否javascript
出於瀏覽器的同源策略限制。同源策略(Sameoriginpolicy)是一種約定,它是瀏覽器最核心也最基本的安全功能,若是缺乏了同源策略,則瀏覽器的正常功能可能都會受到影響。能夠說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。同源策略會阻止一個域的javascript腳本和另一個域的內容進行交互。所謂同源(即指在同一個域)就是兩個頁面具備相同的協議(protocol),主機(host)和端口號(port)html
例: 在 vue.config.js
文件中添加以下配置前端
const webpack = require('webpack');
module.exports = {
devServer: {
open: true, // 在 DevServer 啓動, 且第一次構建完時自動打開網頁
port: 8080, // 端口號
proxy: { // 設置代理
'/api': { // 網關地址
target: 'https://test.com', // 接口的域名
ws: true, // 啓用 websocket
secure: false, // 若是是 https 協議,須要配置這個參數
// 開啓代理:在本地會建立一個虛擬服務端,而後發送請求的數據,並同時接收請求的數據,
// 這樣服務端和服務端進行數據的交互就不會有跨域問題
changOrigin: true, // 跨域需開啓
pathRewrite: { // 重寫地址
'^/api': '' // 將前綴 '/api' 轉爲 '/'
}
}
}
}
}
複製代碼
注: 因爲本質上 script 加載資源的方式是GET, 因此 JSONP 只能用於 GET 請求vue
在HTML標籤裏,一些標籤好比 script、img 這樣的獲取資源的標籤是沒有跨域限制的,利用這一點,咱們能夠這樣幹:java
// 處理成功失敗返回格式的工具
const {successBody} = require('../utli')
class CrossDomain {
static async jsonp (ctx) {
// 前端傳過來的參數
const query = ctx.request.query
// 設置一個cookies
ctx.cookies.set('tokenId', '1')
// query.cb是先後端約定的方法名字,其實就是後端返回一個直接執行的方法給前端,因爲前端是用script標籤發起的請求,因此返回了這個方法後至關於立馬執行,而且把要返回的數據放在方法的參數裏。
ctx.body = `${query.cb}(${JSON.stringify(successBody({msg: query.msg}, 'success'))})`
}
}
module.exports = CrossDomain;
複製代碼
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script type='text/javascript'>
// 後端返回直接執行的方法,至關於執行這個方法,因爲後端把返回的數據放在方法的參數裏,因此這裏能拿到res。
window.jsonpCb = function (res) {
console.log(res)
}
</script>
<script src='http://localhost:9871/api/jsonp?msg=helloJsonp&cb=jsonpCb' type='text/javascript'></script>
</body>
</html>
複製代碼
const request = ({url, data}) => {
return new Promise((resolve, reject) => {
// 處理傳參成xx=yy&aa=bb的形式
const handleData = (data) => {
const keys = Object.keys(data)
const keysLen = keys.length
return keys.reduce((pre, cur, index) => {
const value = data[cur]
const flag = index !== keysLen - 1 ? '&' : ''
return `${pre}${cur}=${value}${flag}`
}, '')
}
// 動態建立script標籤
const script = document.createElement('script')
// 接口返回的數據獲取
window.jsonpCb = (res) => {
document.body.removeChild(script)
delete window.jsonpCb
resolve(res)
}
script.src = `${url}?${handleData(data)}&cb=jsonpCb`
document.body.appendChild(script)
})
}
// 使用方式
request({
url: 'http://localhost:9871/api/jsonp',
data: {
// 傳參
msg: 'helloJsonp'
}
}).then(res => {
console.log(res)
});
複製代碼
// 處理成功失敗返回格式的工具
const {successBody} = require('../utli')
class CrossDomain {
static async iframePost (ctx) {
let postData = ctx.request.body
console.log(postData)
ctx.body = successBody({postData: postData}, 'success')
}
}
module.exports = CrossDomain;
複製代碼
const requestPost = ({url, data}) => {
// 首先建立一個用來發送數據的iframe.
const iframe = document.createElement('iframe')
iframe.name = 'iframePost'
iframe.style.display = 'none'
document.body.appendChild(iframe)
const form = document.createElement('form')
const node = document.createElement('input')
// 註冊iframe的load事件處理程序,若是你須要在響應返回時執行一些操做的話.
iframe.addEventListener('load', function () {
console.log('post success')
})
form.action = url
// 在指定的iframe中執行form
form.target = iframe.name
form.method = 'post'
for (let name in data) {
node.name = name
node.value = data[name].toString()
form.appendChild(node.cloneNode())
}
// 表單元素須要添加到主文檔中.
form.style.display = 'none'
document.body.appendChild(form)
form.submit()
// 表單提交後,就能夠刪除這個表單,不影響下次的數據發送.
document.body.removeChild(form)
}
// 使用方式
requestPost({
url: 'http://localhost:9871/api/iframePost',
data: {
msg: 'helloIframePost'
}
});
複製代碼
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)跨域資源共享 CORS 詳解。看名字就知道這是處理跨域問題的標準作法。CORS有兩種請求,簡單請求和非簡單請求。node
只要同時知足如下兩大條件,就屬於簡單請求。webpack
請求方法是如下三種方法之一:web
HTTP的頭信息不超出如下幾種字段:json
後端segmentfault
// 處理成功失敗返回格式的工具
const {successBody} = require('../utli')
class CrossDomain {
static async cors (ctx) {
const query = ctx.request.query
// *時cookie不會在http請求中帶上
ctx.set('Access-Control-Allow-Origin', '*')
ctx.cookies.set('tokenId', '2')
ctx.body = successBody({msg: query.msg}, 'success')
}
}
module.exports = CrossDomain;
複製代碼
前端什麼也不用幹,就是正常發請求就能夠,若是須要帶cookie的話,先後端都要設置一下
fetch(`http://localhost:9871/api/cors?msg=helloCors`, {
// 須要帶上cookie
credentials: 'include',
// 這裏添加額外的headers來觸發非簡單請求
headers: {
't': 'extra headers'
}
}).then(res => {
console.log(res)
});
複製代碼