前端面试题(三)—— 跨域
一、什么是跨域
1、跨域的产生
在Web开发中,一个网页请求另一个域(域名、协议、端口号任一不同)的资源,就会发生跨域。
2、跨域请求
跨域请求是指在浏览器中执行的请求,其目标资源的域名、协议或端口与当前页面不同。
3、跨域资源共享(CORS)
跨域资源共享(CORS)是一种机制,它允许在一个源(域名、协议、端口)上的网页应用程序访问另一个源上的部分资源。
二、跨域资源共享(CORS)的工作原理
1、客户端发起跨域请求
当浏览器的前端代码中发起了一个跨域请求时,浏览器会首先发送 OPTIONS 预检请求(Preflight Request)给目标服务器,以确定是否允许进行跨域请求。
2、服务器响应预检请求
目标服务器接收到 OPTIONS 请求后,会进行预检查,检查是否允许当前域名的请求。服务器会在响应中包含一些 CORS 相关的头部信息,如 Access-Control-Allow-Origin、Access-Control-Allow-Methods 等。
3、浏览器检查响应头部
浏览器接收到服务器的响应后,会检查响应头部中的 CORS 相关信息,如果允许跨域请求,则浏览器会发送实际的请求给服务器,否则会阻止请求。
简单说👀
浏览器先发送 OPTIONS 预检请求给服务器
服务器在 header 加上 CORS 相关信息返给浏览器
浏览器看看能不能跨域,能就发实际请求,不能就拉倒
三、前端如何处理跨域请求
1、JSONP(仅限 GET 请求)
JSONP 是一种通过动态创建 <script>
标签实现跨域请求的方法。服务器返回的数据被包裹在一个 JavaScript 函数调用中,前端通过指定回调函数来获取数据。JSONP 的缺点是仅支持 GET 请求,并且容易受到安全漏洞的影响。
例:有一个页面 index.html
,需要从另一个域名为 example.com
的服务器上获取数据
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JSONP Example</title> </head> <body> <div id="data"></div> <script> // 创建一个回调函数,用于处理 JSONP 请求的响应数据 function handleResponse(data) { document.getElementById('data').innerHTML = data.message; } // 动态创建一个 script 标签,并指定跨域请求的地址和回调函数名 var script = document.createElement('script'); script.src = 'http://example.com/api/data?callback=handleResponse'; document.head.appendChild(script); </script> </body> </html>
在上面的代码中,动态创建了一个 <script>
标签,并将 src
属性设置为跨域请求的地址 ,地址中包含了回调函数名 handleResponse,以便在服务器返回数据时,在此函数中处理数据。
另外,服务端响应的内容格式应该是 handleResponse({"message": "Hello, world!"}),数据包在回调函数里,这样客户端就能正确处理了。
2、CORS
使用 CORS 可以实现跨域资源共享,通过在服务器端设置响应头部来允许特定域名的跨域请求。前端无需额外处理,浏览器会自动处理 CORS 相关的预检请求和实际请求。
对于开发者来说,只需要在服务器端设置相应的 CORS 头部信息,告知浏览器是否允许跨域访问即可。常见的 CORS 头部信息包括:
Access-Control-Allow-Origin
:指定允许跨域访问的来源域名,可以是单个域名、多个域名、或者是通配符*
。Access-Control-Allow-Methods
:指定允许的 HTTP 方法。Access-Control-Allow-Headers
:指定允许的自定义头部。
3、代理
前端通过自己的服务器端建立一个代理服务器来转发请求,实现跨域访问。前端发送请求给自己的服务器,服务器再将请求转发给目标服务器,并将响应返回给前端。这种方式可以绕过浏览器的同源策略限制,但会增加服务器的负担和延迟。
4、WebSocket
WebSocket 是一种全双工通信协议,可以在客户端和服务器之间建立持久的连接,实现跨域通信。由于 WebSocket 不受同源策略的限制,可以直接在前端代码中使用 WebSocket 进行跨域通信。