目录
是指在浏览器环境中,当一个请求的源(Origin)与目标资源的源不相同,就发生了跨域。具体来说,跨域是指在协议、域名或端口这三者中,只要有一个不同,就被认为是跨域。
是浏览器的一种安全机制,它限制了不同源之间的交互。同源策略要求网页只能通过脚本访问同一源的内容,不能获取其它源的数据,这样可以防止恶意网站窃取用户的信息。
跨域问题可能会出现在前端与后端进行交互时,例如使用 Ajax 发起请求获取数据。如果前端页面的源与后端接口的源不同,就会触发浏览器的跨域限制,导致请求失败。
所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。如果缺少了同源策略,浏览器很容易受到XSS
、CSRF
等攻击。
1. JSONP(JSON with Padding):通过动态创建 `<script>` 标签,利用 `<script>` 标签可以跨域请求数据的特性,将响应数据包装在回调函数中返回,通过调用回调函数来获取数据。
2. CORS(Cross-Origin Resource Sharing):通过服务端设置响应头,允许特定的源访问资源。应在服务端对请求进行处理,在响应头中添加跨域相关的信息,例如 `Access-Control-Allow-Origin`、`Access-Control-Allow-Methods` 等。
3. 代理:通过服务器端进行中转,将前端的请求发送到同源的后端,由后端代为请求目标资源,并将结果返回给前端。
4. WebSocket:WebSocket 是 HTML5 提供的一种在单个 TCP 连接上进行全双工通信的协议,它没有跨域限制。
需要根据具体情况选择适合的跨域解决方案,确保数据的安全性和正确性。
1. 跨域访问策略:浏览器的同源策略对于 `<script>` 标签的跨域请求有一定的例外。同源策略要求在页面中使用 JavaScript 访问资源时,要求协议、域名和端口都要相同。但 `<script>` 标签的 `src` 属性不受同源策略的约束,可以通过该属性加载不同源的脚本文件。
2. 脚本标签的特性:当浏览器解析到 `<script>` 标签时,会将其引用的脚本文件当做普通的 JavaScript 代码执行。对于普通的 JavaScript 代码而言,没有同源限制,可以访问任何资源。因此,即使 `<script>` 标签加载的资源与当前页面的源不同,也可以正常执行脚本文件。
因此,利用 `<script>` 标签的这两个特性,可以通过动态创建 `<script>` 标签,给 `src` 属性设置跨域的 URL,从而实现在浏览器中跨域请求资源的效果。这就是 JSONP 这种利用 `<script>` 标签进行跨域请求的基本原理。当然,这种方式只适用于 GET 请求,并且需要服务器端进行相应的处理,将返回结果封装到一个预先定义好的回调函数中传递给前端页面。
function handleResponse(response) {
console.log('Response:', response);
// 在这里处理响应数据
}
function getData() {
var script = document.createElement('script');
script.src = 'http://api.example.com/data?callback=handleResponse';
document.head.appendChild(script);
}
在上述代码中,通过动态创建?<script>
?标签,将请求的 URL 设置为带有?callback
?参数的 URL。这个?callback
?参数的值是一个全局函数名,用于接收响应数据。
from django.http import HttpResponse
def data(request):
response_data = { "result": "success", "data": "Some data" }
# 使用 JSONP
callback = request.GET.get('callback')
if callback:
response_data = f'{callback}({response_data})'
# 设置响应头
response = HttpResponse(response_data, content_type='application/javascript')
response['Access-Control-Allow-Origin'] = '*' # 设置允许所有域名访问,可根据需要进行配置
return response
在上述代码中,根据前端传递的?callback
?参数,判断是否为 JSONP 请求。如果是 JSONP 请求,将响应数据包装在回调函数中返回。
在示例中,前端调用?getData()
?函数来发起跨域请求,通过动态创建?<script>
?标签并指定 URL,然后将该标签添加到页面头部。当响应返回时,服务器返回的内容会被解析执行,并通过全局函数?handleResponse
?接受响应数据。
需要注意的是,JSONP 只支持 GET 请求,并且存在一些安全风险,因此在使用时应谨慎考虑,并确保可信的数据源和回调函数。
python 终端中输入?
pip install django-cors-headers
# 应用
INSTALLED_APPS = [
? ?'corsheaders'
]
# 中间件
MIDDLEWARE = [
? ?'corsheaders.middleware.CorsMiddleware'
]
?
CORS_ORIGIN_ALLOW_ALL = True
注意
POST
请求数据 , 要注销
MIDDLEWARE = [
? ?'django.middleware.security.SecurityMiddleware',
? ?'django.contrib.sessions.middleware.SessionMiddleware',
? ?'django.middleware.common.CommonMiddleware',
? ?# 'django.middleware.csrf.CsrfViewMiddleware',
? ?'django.contrib.auth.middleware.AuthenticationMiddleware',
? ?'django.contrib.messages.middleware.MessageMiddleware',
? ?'django.middleware.clickjacking.XFrameOptionsMiddleware',
? ?'corsheaders.middleware.CorsMiddleware'
通过 WebSocket 可以在前端与后端进行实时通信:
const socket = new WebSocket('ws://example.com/socket');
socket.addEventListener('open', () => {
console.log('Socket connected');
// 发送消息
socket.send('Hello, server!');
});
socket.addEventListener('message', event => {
console.log('Message from server:', event.data);
// 在这里处理收到的消息
});
socket.addEventListener('error', error => {
console.error('Socket error:', error);
});
socket.addEventListener('close', event => {
console.log('Socket closed with code:', event.code);
});
在上述代码中,使用?WebSocket
?构造函数创建一个 WebSocket 连接对象,并指定服务器地址为?ws://example.com/socket
。通过?addEventListener
?方法监听?open
、message
、error
?和?close
?事件,在相应事件发生时打印日志或处理返回的消息。
(使用 Django Channels 框架):
import json
from channels.generic.websocket import WebsocketConsumer
class SocketConsumer(WebsocketConsumer):
def connect(self):
self.accept()
def disconnect(self, close_code):
pass
def receive(self, text_data):
data = json.loads(text_data)
# 在这里进行逻辑处理,然后发送消息
response_data = { "result": "success", "data": "Some data" }
self.send(text_data=json.dumps(response_data))
在上述代码中,使用 Django Channels 框架实现一个 WebSocketConsumer,在?connect
?方法中接受 WebSocket 连接,disconnect
?方法用于在连接关闭时进行清理工作。通过?receive
?方法接收前端发送的消息,然后进行处理,处理完成后再通过?self.send
?方法发送响应消息。
通过WebSocket,我们可以在前后端之间进行双向通信,实现实时交互,这是传统的 HTTP 请求所不能实现的。需要注意的是,WebSocket 连接需要服务器端进行支持,后端需对 WebSocket 进行相应的配置和处理。