Express演示跨域解决

一、 同源、非同源/跨域

仅协议、ip、端口完全相同的地址才算同源请求,三者任意一个不一样为非同源请求/跨域请求。

二、跨域行为的限制

  1. 无法读取到非同源的iframe内容
    在这里插入图片描述

  2. 无法读取到非同源cookie

  3. 无法获取非同源ajax请求数据

在这里插入图片描述

三、Ajax跨域解决

浏览器抛出了跨域请求错误,并不是代表跨域请求没有发出去,而是发出去了并且响应成功,但是浏览器会在把数据交给js脚本之前会做校验比对。如果校验通过,则继续把响应数据交给Js脚本,否则会抛出跨域异常。

  • 浏览器的校验策略是什么?

如果是跨域请求,在响应返回时需要在响应头中设置如下响应头字段,值是什么?值就是请求头中的Origin,Origin请求头表示发起请求的源。

Access-Control-Allow-Origin :xxx

在这里插入图片描述
这里请求头字段中的Origin 仅会包含协议、域名、端口,主要作用就是用于帮助服务器识别来源域。
如果服务器允许这个源访问,则需要在响应头中设置 Access-Control-Allow-Origin :http://127.0.0.1:5500,注意,这里的格式必须完全保持和请求头中的Origin一致。

  • 代码示例

前端示例代码:

    function getAjaxData(){
        $.ajax({
           url:"http://127.0.0.1:3000/list",
           type:"get",
           success(res){
            console.log("ajaxData",res);
           } 
        })
    }

Express服务修改:

app.get('/list',(res,req) => {
    req.header('Access-Control-Allow-Origin','http://127.0.0.1:5500')
    req.send(listData)
})

当响应头添加允许跨域标识字段之后,此时校验规则通过,Js脚本可以获取数据。
在这里插入图片描述

  • 预检请求发送

当发送ajax请求时自定义了header,会发现此时又跨域报错了
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

而且发现浏览器多发了一次请求,这就是预检请求。

预检请求什么时候发出?

  1. 当跨域请求的请求方法非 GET PUT DELETE时。
  2. 当自定义了Http Header时。
  3. 当请求内容类型非 application/x-www-form-urlencoded、multipart/form-data、text/plain时。

验证预检请求:

 function getAjaxData(){
        $.ajax({
           url:"http://127.0.0.1:3000/list",
           type:"post",
           headers:{
                SaToken:"token"
           },
           contentType: 'application/json', // 告诉服务器发送的数据类型
           dataType: 'json',
           data:JSON.stringify({id:1}),
           success(res){
            console.log("ajaxData",res);
           } 
        })
    }

这里我自定义了header且修改了请求content-type字段,当修改了这个字段时,浏览器发现不是默认允许的三种内容类型,就在预检请求中添加了content-type头。

在这里插入图片描述

此时服务器需要继续设置新的响应头来告诉浏览器允许跨域。

Express代码修改:

app.options('/list',(res,req) =>{
    req.header('Access-Control-Allow-Headers','content-type,satoken')
    req.header('Access-Control-Allow-Origin','http://127.0.0.1:5500')
    req.send("OK");
})

app.post('/list',(res,req) => {
    req.header('Access-Control-Allow-Origin','http://127.0.0.1:5500')
    req.send(listData)
})

在这里插入图片描述

此时可以看到预检请求的响应头中包含了请求头所需要的校验header。

继续验证PUT请求方法

    function getAjaxData(){
        $.ajax({
           url:"http://127.0.0.1:3000/list",
           type:"put",
           dataType: 'json',
           data:JSON.stringify({id:1}),
           success(res){
            console.log("ajaxData",res);
           } 
        })
    }

在这里插入图片描述
注意,此时浏览器报错提示的是Access-Control-Allow-Methods头缺失。

Express服务代码修改:

app.options('/list',(res,req) =>{
    req.header('Access-Control-Allow-Headers','content-type,satoken')
    req.header('Access-Control-Allow-Origin','http://127.0.0.1:5500')
    req.header('Access-Control-Allow-Methods','*')
    req.send("OK");
})

设置了Access-Control-Allow-Methods响应头之后可以保证预检请求通过。
这里需要注意的是,在预检请求的响应头设置了相关跨域头之后,在实际请求的响应头上也需要设置相关允许跨域字段。

  • 跨域请求响应头暴露

后端在自定义设置响应头时,如果是跨域请求,且没有设置相关暴露响应头字段,则前端无法获取响应头数据

app.put('/list',(res,req) => {
    req.header('Access-Control-Allow-Origin','http://127.0.0.1:5500')
    req.header('myHeader',"hello world")
    req.send(listData)
})

    function getAjaxData(){
        $.ajax({
           url:"http://127.0.0.1:3000/list",
           type:"put",
           dataType: 'json',
           data:JSON.stringify({id:1}),
           success(res, textStatus, jqXHR){
            console.log("ajaxData",res);
            console.log('Response Headers:', jqXHR.getAllResponseHeaders());
           } 
        })
    }

在这里插入图片描述

设置Express请求允许暴露跨域请求获取响应头

app.put('/list',(res,req) => {
    req.header('Access-Control-Allow-Origin','http://127.0.0.1:5500')
    req.header('Access-Control-Expose-Headers', '*');
    req.header('myHeader',"hello world")
    req.send(listData)
})

在这里插入图片描述
此时控制台可以打印出所有的跨域请求设置的响应头。

四、跨域请求其他解决方案

跨域方案说明
JsonP只能支持Get请求,依赖Script标签,局限性大
devServer脚手架开发环境配置devServerProxy代理,优雅解决

五、跨域请求Cookie携带问题

  1. 跨域未跨站请求,服务器设置cookie的domain为.xxx.com顶级域名,且Cookie属性为Secure。
    当发送未跨站请求时,会自动携带cookie。

  2. 跨域且跨站,响应端设置Cookie时,需要为Secure属性,SameSite=None,且前端需要设置withCredentials ,后端响应头设置允许跨域请求携带Cookie。

以下是几种常见的解决问题的代码示例: 1. CORS(服务端配置) 在服务端的响应中添加 CORS 相关的响应头,允许来自指定源的请求。 ```java // Java - Spring Boot 示例 @Configuration public class CorsConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://example.com") // 允许的源地址 .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法 .allowedHeaders("*") // 允许的请求头 .allowCredentials(true); // 是否允许发送 cookie } }; } } ``` 2. JSONP(前端代码) 通过动态创建 `<script>` 标签来获取数据。 ```javascript function handleResponse(data) { // 处理响应数据 } var script = document.createElement('script'); script.src = 'http://example.com/api?callback=handleResponse'; document.body.appendChild(script); ``` 3. 代理服务器(服务端代码) 通过服务器端代理转发请求,解决问题。 ```javascript // Node.js - Express 示例 const express = require('express'); const request = require('request'); const app = express(); const API_URL = 'http://example.com/api'; app.get('/api', (req, res) => { const url = API_URL + req.url; req.pipe(request(url)).pipe(res); }); app.listen(3000, () => { console.log('Proxy server is running on port 3000'); }); ``` 4. WebSocket(前端代码) 使用 WebSocket 进行通信。 ```javascript // 前端代码 const socket = new WebSocket('ws://example.com/socket'); socket.onopen = function() { // 连接成功,可以进行通信 socket.send('Hello Server!'); }; socket.onmessage = function(event) { // 处理接收到的消息 console.log('Received message:', event.data); }; ``` 这些示例代码只是简单的演示,实际解决问题时,需要根据具体的应用场景和技术栈选择合适的解决方案。同时,还需注意安全性和适用性等方面的考虑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值