Luffy - 解決跨域問題
Luffy - 解決跨域問題
一:跨域請求
0. 跨域問題的出現
問題出現:前後端來自同一個IP
的不同埠
一種奇葩的解決方法:開發的時候前後端分離,部署的時候不分離
1.同源策略
① 簡介
同源策略,是瀏覽器為了保護使用者資訊保安的一種安全機制
所謂的同源就是指代通訊的兩個地址(例如服務端介面地址與瀏覽器客戶端頁面地址)之間比較,是否協議、域名(IP)和埠相同
不同源的客戶端指令碼[
javascript
]在沒有得到服務端的明確授權的情況下,瀏覽器會拒絕顯示服務端資訊提供給前端ajax/axios
前端地址:http://www.4399.com/index.html | 是否同源 | 原因 |
---|---|---|
http://www.4399.com/user/login.html | 是 | 協議、域名、埠相同 |
http://www.4399.com/about.html | 是 | 協議、域名、埠相同 |
https://www.4399.com/user/login.html | 否 | 協議不同 ( https和http ) |
http:/www.4399.com:5000/user/login.html | 否 | 埠 不同( 5000和80) |
http://doc.4399.com/user/login.html | 否 | 域名不同 ( doc和www ) |
http://www.4399.top/user/login.html | 否 | 域名不同 ( com和top ) |
2. CORS(跨域資源共享)簡介
CORS
是一個W3C
標準,全稱是"跨域資源共享",它允許瀏覽器向跨源的後端伺服器發出ajax
請求,從而克服了AJAX
只能同源使用的限制。
實現CORS
主要依靠後端伺服器中響應資料中設定響應頭資訊返回的
CORS
需要瀏覽器和伺服器同時支援。目前,所有瀏覽器都支援該功能,IE瀏覽器不能低於IE10
。
整個
CORS
通訊過程,都是瀏覽器自動完成,不需要使用者參與。對於開發者來說,CORS
通訊與同源的AJAX
通訊沒有差別,程式碼完全一樣。瀏覽器一旦發現AJAX
請求跨源,就會自動新增一些附加的頭資訊,有時還會多出一次附加的請求,但使用者不會有感覺。
因此,實現
CORS
通訊的關鍵是伺服器。只要伺服器實現了CORS
介面,就可以跨源通訊
容易混淆的點:
CORS
:跨域資源共享CSRF
:跨站請求偽造XSS
:跨站指令碼攻擊
3. CORS
基本流程
瀏覽器將CORS
請求分成兩類:簡單請求(simple request
)和非簡單請求(not-so-simple request
)
- 瀏覽器發出
CORS
簡單請求,只需要在頭資訊之中增加一個Origin
欄位 - 瀏覽器發出
CORS
非簡單請求,會在正式通訊之前,增加一次HTTP
查詢請求,稱為”預檢”請求(preflight
) - 覽器先詢問伺服器,當前網頁所在的域名是否在伺服器的許可名單之中,以及可以使用哪些
HTTP
動詞和頭資訊欄位 - 只有得到肯定答覆,瀏覽器才會發出正式的
XMLHttpRequest
請求,否則就報錯。
4. 解決跨域問題的3種方法
- 前端解決(通過代理解決)
- 自己解決(自己寫程式碼)
- 藉助第三方模組(
django-cors-headers
)
5. CORS
兩種請求詳解
只要同時滿足以下兩大條件,就屬於簡單請求
-
① 請求方法是以下三種方法之一
HEAD
GET
POST
-
②
HTTP
的頭資訊不超出以下幾種欄位Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type
:只限於三個值application/x-www-form-urlencoded
、multipart/form-data
、text/plain
-
凡是不同時滿足上面兩個條件,就屬於非簡單請求
6. 瀏覽器對這兩種請求的處理,是不一樣的
簡單請求和非簡單請求的區別
- 簡單請求:發1次請求
- 非簡單請求:發2次請求,在傳送資料之前會先發1次請求用於做“預檢”看後端是否允許,只有“預檢”通過後才再傳送1次請求用於資料傳輸。
請求方式:OPTIONS
預檢:
- 檢查如果通過則允許傳輸資料,檢查不通過則不再傳送真正想要傳送的訊息
如何預檢:
- 如果複雜請求是
PUT
等請求,則服務端需要設定允許某請求,否則“預檢”不通過
Access-Control-Request-Method
- 如果複雜請求設定了請求頭,則服務端需要設定允許某請求頭,否則“預檢”不通過
Access-Control-Request-Headers
二:解決跨域問題(服務端)
【簡單請求】
1. 原Django專案:apps/user/views.py
from django.http import JsonResponse
def test(request):
obj = JsonResponse({'name': 'Darker', 'age': '18'})
# 值針對簡單請求
obj['Access-Control-Allow-Origin'] = '*' # 允許所有IP訪問
return obj
2. 原Django專案:apps/user/urls.py
from django.urls import path
from user import views
urlpatterns = [
path('test/', views.test),
]
3. 原Django專案:dev.py
中註釋掉CSRF
4. 再建立1個Django專案(用另外的埠)
① templates
中建立index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<button id="btn">點我</button>
</body>
<script>
$('#btn').click(function () {
$.ajax({
url: 'http://127.0.0.1:8000/user/test/',
method: 'get',
success: function (data) {
console.log(data)
}
})
})
</script>
</html>
② views.py
from django.shortcuts import render
def index(request):
return render(request, 'index.html')
③ urls.py
from django.urls import path
from app01 import views
urlpatterns = [
path('test/', views.index),
]
【非簡單請求】
原Django專案apps/user/views.py
from django.http import JsonResponse
def test(request):
obj = JsonResponse({'name': 'Darker', 'age': '18'})
if request.method == 'OPTIONS':
obj['Access-Control-Allow-Headers'] = 'Content-Type,authorization' # 或者填寫 *
obj['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8002' # 8002埠是當前專案的
return obj
新Django專案templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<button id="btn">點我</button>
</body>
<script>
$('#btn').click(function () {
let obj = {name: 'Darker'}
$.ajax({
url: 'http://127.0.0.1:8000/user/test/',
method: 'post',
contentType: 'application/json',
headers: {authorization: 'Darker'},
data: JSON.stringify(obj),
success: function (data) {
console.log(data)
}
})
})
</script>
</html>
【中介軟體處理】
① 在原Django專案的根路徑建立mymiddle.py
- 自定義中介軟體
from django.utils.deprecation import MiddlewareMixin
class CoreMiddle(MiddlewareMixin):
def process_response(self, request, response):
if request.method == 'OPTIONS':
response['Access-Control-Allow-Headers'] = 'Content-Type, authorization' # 如果是 * 就代表全部IP都可以訪問
response['Access-Control-Allow-Origin'] = '*'
return response
② 在原Django專案的dev.py
的中介軟體中新增自定義中介軟體
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'mymiddle.CoreMiddle', # 這一句
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
③ 原Django專案apps/user/views
中替換成如下程式碼
from django.http import JsonResponse
def test(request):
return JsonResponse({'name': 'Darker', 'age': '18'})
三:解決跨域問題(第三方)
1. 後端配置
① 後端安裝跨域模組
pip install django-cors-headers
② 到dev.py
中進行註冊
INSTALLED_APPS = (
...
'corsheaders'
)
③ 到dev.py
中新增中介軟體
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware', # 這個是原本就存在的
...
]
④ 到dev.py
中新增如下程式碼
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
# CORS_ORIGIN_WHITELIST = (
# 'http://127.0.0.1:8080',
# )
CORS_ALLOWED_ORIGINS_REGEXES=[
r'^http://.*?$',
]
# CORS_ORIGIN_REGEXES_WHITELIST = (
# r'^http://.*?$',
# )
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
'VIEW',
)
CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
)
⑤ 設定dev.py
的ALLOWED_HOSTS
ALLOWED_HOSTS = ['*']
2. 後端測試
① (測試 - 後臺)到apps/user/views
中替換成如下程式碼
from django.http import JsonResponse
def test(request):
return JsonResponse({'name': 'Darker', 'age': '18'})
② (測試 - 後臺)到apps/user/urls中替換成如下程式碼
from django.urls import path
from user import views
urlpatterns = [
path('test/', views.test),
]
③ 啟動專案
python manage.py runserver 127.0.0.1:8000
④ 訪問測試
3. 前端測試
①(測試 - 前臺)App.vue
中換成如下程式碼
<template>
<div id="app">
<router-view/>
{{name}}
</div>
</template>
<script>
export default {
data () {
return {
name: []
}
},
mounted () {
this.$axios.get(this.$settings.base_url + '/user/test/').then(res => {
this.name = res.data
})
}
}
</script>
② 啟動專案
npm run serve
4. 測試效果
四:解決跨域問題(前端)
1. 前端App.vue
<template>
<div id="home">
<h1>我是主頁</h1>
<h2>{{info}}</h2>
</div>
</template>
<script>
export default {
name: 'Home',
data () {
return {
info: []
}
},
mounted () {
this.$axios.get('/moreClassicList?sortId=1&showType=3').then(res => {
console.log(res.data)
})
}
}
</script>
<style scoped>
</style>
2. 前端專案根路徑的vue.config.js
const webpack = require("webpack");
module.exports = {
configureWebpack: {
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
"window.$": "jquery",
Popper: ["popper.js", "default"]
})
]
},
devServer: {
proxy: {
'/ajax': {
target: 'https://m.maoyan.com/',
changeOrigin: true
},
'/user': {
target: 'http://127.0.0.1:8000',
changeOrigin: true
}
}
}
};
相關文章
- 解決跨域問題跨域
- 搞懂:前端跨域問題JS解決跨域問題VUE代理解決跨域問題原理前端跨域JSVue
- WebSocket跨域問題解決Web跨域
- Java解決跨域問題Java跨域
- Flask解決跨域問題Flask跨域
- CROS 解決跨域問題ROS跨域
- SignalR跨域問題解決SignalR跨域
- cors解決跨域問題CORS跨域
- 深入跨域問題(3) – 利用 JSONP 解決跨域跨域JSON
- 深入跨域問題(3) - 利用 JSONP 解決跨域跨域JSON
- 深入跨域問題(2) - 利用 CORS 解決跨域跨域CORS
- Nginx解決前端跨域問題 CORS跨域配置Nginx前端跨域CORS
- 跨域問題及解決方案跨域
- 輕鬆解決跨域問題跨域
- thinkphp 5 跨域問題解決PHP跨域
- JAVA | Java 解決跨域問題Java跨域
- 跨域問題解決辦法跨域
- SpringBoot跨域問題解決方案Spring Boot跨域
- 解決JS跨域訪問的問題JS跨域
- vue webpack配置解決跨域問題VueWeb跨域
- 前端跨域問題及其解決方案前端跨域
- Flutter Web 跨域問題解決方案FlutterWeb跨域
- 跨域問題,解決方案 – CORS方案跨域CORS
- nginx /Java 解決跨域問題方案NginxJava跨域
- 前端怎麼解決跨域問題前端跨域
- spring mvc解決ajax跨域問題SpringMVC跨域
- 前端解決跨域問題總結前端跨域
- Django專案解決跨域問題Django跨域
- nginx 解決圖片跨域問題Nginx跨域
- 解決常見介面跨域問題跨域
- 前端http請求跨域問題解決前端HTTP跨域
- Vue中跨域問題解決方案1Vue跨域
- Nuxt使用axios跨域問題解決方法UXiOS跨域
- 解決跨域問題 barryvdh/Laravel-cors跨域LaravelCORS
- 使用Nginx來解決跨域的問題Nginx跨域
- Spring boot 解決跨域問題配置類Spring Boot跨域
- VUE 呼叫 flask 介面,解決跨域問題VueFlask跨域
- SpringBoot解決前後端跨域問題Spring Boot後端跨域