跨域问题,解决方案(前后端代码)

发布时间:2024年01月14日

目录

跨域(Cross-Origin)

同源策略(Same-Origin Policy)

常见的解决方案

示例

JSONP

脚本(script)标签可以跨域请求资源的原因主要有两个:

前端代码:

后端代码(服务端返回的响应):

Django框架后端跨域

WebSocket

前端代码:

后端代码


跨域(Cross-Origin)

是指在浏览器环境中,当一个请求的源(Origin)与目标资源的源不相同,就发生了跨域。具体来说,跨域是指在协议、域名或端口这三者中,只要有一个不同,就被认为是跨域。

同源策略(Same-Origin Policy)

是浏览器的一种安全机制,它限制了不同源之间的交互。同源策略要求网页只能通过脚本访问同一源的内容,不能获取其它源的数据,这样可以防止恶意网站窃取用户的信息。

跨域问题可能会出现在前端与后端进行交互时,例如使用 Ajax 发起请求获取数据。如果前端页面的源与后端接口的源不同,就会触发浏览器的跨域限制,导致请求失败。

所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。如果缺少了同源策略,浏览器很容易受到XSSCSRF等攻击。

常见的解决方案

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 连接上进行全双工通信的协议,它没有跨域限制。

需要根据具体情况选择适合的跨域解决方案,确保数据的安全性和正确性。

示例
JSONP
脚本(script)标签可以跨域请求资源的原因主要有两个:

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 请求,并且存在一些安全风险,因此在使用时应谨慎考虑,并确保可信的数据源和回调函数。

Django框架后端跨域

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

通过 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?方法监听?openmessageerror?和?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 进行相应的配置和处理。

文章来源:https://blog.csdn.net/kkkys_kkk/article/details/135577403
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。