express框架:同源策略、解决跨域问题

同源策略与跨域解决

1、同源策略概念

同源策略(Same-Origin Policy)最早由NEtscape公司提出,是浏览器的一种安全策略。同源指的是协议、域名、端口号必须完成相同违背同源策略就是跨域

案例

  • server.js
const express = require('express')

const app = express()

app.get('/home',(request,response) => {
    // 当url为127.0.0.1:9000/home时,响应一个页面
    response.sendFile(__dirname + '/index.html')
})

app.get('/data',(request,response) => {
	// 当页面index.html中按钮被点击后响应数据
    response.send('用户数据')
})

// 监听9000端口
app.listen('9000',() => {
    console.log("服务启动,监听端口中...");
})


  • 页面文件index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>测试同源策略</title>
</head>

<body>
    <h3>hello</h3>
    <button>点击获取用户数据</button>
    <script>
        const btn = document.querySelector('button')
        btn.onclick = function () {
            const xhr = new XMLHttpRequest()
            // 这里满足同源策略,所以url可以简写:这里省略了域名http://127.0.0.1:9000
            xhr.open('get', '/data')
            xhr.send()
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (xhr.status >= 200 && xhr.status < 300) {
                        console.log(xhr.response);
                    }
                }
            }
        }
    </script>
</body>

</html>

浏览器输入127.0.0.1:9000/home,得到如下结果
在这里插入图片描述
点击按钮,在控制台可以看到获取到了服务器响应的数据
在这里插入图片描述

2、解决跨域问题

2.1 方法一:jsonp解决跨域问题

  • jsonp是什么
    jsonp(JSON with Padding),是一个非官方的跨域解决方法,纯粹凭借程序员的聪明才智开发处理,只支持get请求
  • jsonp工作原理
    在网页有一些标签自带跨域能力,例如img、link、iframe、script
    JSONP就是利用script标签的跨域能力来发送请求的。
原生html实现

例如:

案例一:

  • 测试用html文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title> </head> <body>
    <div id="result"></div>
    <!--跨域请求-->
    <!--vscode中使用liveserver打开网页时,端口号为5050,所以下面的script标签中确实跨域了-->
    <script src="http://127.0.0.1:8000/jsonp-test"></script>

</body>
 </html>
  • server.js文件【使用express框架模仿的服务器】
const express = require('express')

const app = express()

app.get('/jsonp-test',(request,response) => {
	// 响应一个字符串
    response.send('hello jsonp')
})

app.listen('8000',()=>{
    console.log("服务启动,监听端口中..."); })

得到的结果报错,意思为不被期待的标识符,说的是script标签不能识别普通字符串
在这里插入图片描述
因为响应到页面的是一个字符串,而一个script标签是不能解析字符串的,而需要响应一个js代码,因此,server.js需要响应一个js代码的字符串


const app = express()

app.get('/jsonp-test',(request,response) => {
    // const data = {
    //     name:"小刘"
    // }
    response.send('console.log("hello jsonp")')
    // response.send(`handle(${data})`) 
})

app.listen('8000',()=>{
    console.log("服务启动,监听端口中..."); 
 })

成功获取结果
在这里插入图片描述
打开浏览器网络,可以看到成功获取响应了,并且响应式js代码
在这里插入图片描述

案例二:

  • server.js
const express = require('express')

const app = express()

app.get('/jsonp-test',(request,response) => {
    const data = {
        name:"小刘"
    }

    // 将data转换为json字符串形式
    const str = JSON.stringify(data)
    // 利用模板字符串,将调用方法以js代码的格式响应过去
    response.send(`handle(${str})`)
})

app.listen('8000',()=>{
    console.log("服务启动,监听端口中...");
})
  • test.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title> </head> <body>
    <div id="result">

    </div>
    <script>
        // 将方法声明在这,而方法调用通过script标签跨域传进来
        function handle(data){
            const result = document.getElementById('result')
            result.innerHTML = data.name
        }
    </script>
    <!-- 实现跨域 -->
    <script src="http://127.0.0.1:8000/jsonp-test"></script> 
</body> 
</html>

在这里插入图片描述
查看浏览器网络,接收到的响应是一个方法调用的js代码,并且方法中的参数也是由另一端的服务器传过来的。
在这里插入图片描述

  • 具体案例使用

  • 案例描述:输入款输入用户名,判断用户名是否存在(这句逻辑就不写了)不存在,在输入框下显示"用户不存在",输入框样式改变。
    步骤:
    (1)动态创建一个script标签
    (2)设置script的URL
    (3)将script标签添加到页面中

  • 模拟服务器端代码【express框架实现】

const express = require('express')

const app = express()

app.get('/test',(request,response) => {
    // 这里省略逻辑判断
    const data = {
        exist:1,
        msg:'用户名已经存在'
    }

    // 将data转换为json字符串形式
    const str = JSON.stringify(data)
    // 利用模板字符串,将调用方法以js代码的格式响应过去
    response.send(`handle(${str})`)
})

app.listen('8000',()=>{
    console.log("服务启动,监听端口中...");
})
  • 页面代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    用户名:<input type="text" id="username">
    <p></p>
    <script>
        const input = document.querySelector('input')
        const p = document.querySelector('p')

        // 声明函数
        function handle(data){
            input.style.border = 'solid 3px #f00'
            p.innerHTML = data.msg;
        }

        input.onblur = function(){
            // 获取用户的输入值
            let username = this.value;
            // console.log(this); // this标识的input整个标签元素
            console.log(username);
            // 创建script标签
            const script = document.createElement('script')
            // 设置标签的src属性
            script.src = 'http://127.0.0.1:8000/test'
            // 将script节点添加到文档中
            document.body.appendChild(script)
        }
    </script>
</body>
</html>

效果展示:
请添加图片描述

jquery实现
$.ajax({
	url:"http://www.test.com:8080/login",
	type:'get', // jsonp只支持get请求
	dataType:'jsonp', // 请求类型为jsonp
	jsonpCallback:'handleCallback', // 自定义函数
	data:{}, // 要传送的数据
})
vue实现
this.$http.jsonp('http://www.omain2.com:8080/login',{
	params:{},
	jsonp:'handleCallback',
}).then((res)=>{
	console.log(res);
})

2.2 方法二:设置CORS响应头实现跨域

  • CORS是什么
    CORS(Cross-Oringin Resource Sharing),跨域资源共享。CORS是官方的跨域解决方案。

CORS特点是不需要再客户端做人任何特殊的操作,完全在服务器中进行处理,支持get和post请求,跨域资源共享标准增添了一组HTTP首部字段,允许服务器生命哪些源站通过浏览器有权限访问哪些资源。

  • CORS工作原理
    CORS通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应后就会对响应’放行’

  • CORS的使用

server.js

// 引入express
const { response } = require('express')
const express = require('express')

// 创建应用对象
const app = express()

app.get('/server',(request,response) => {
    // 设置响应头,实现跨域,第二个参数是指定可以跨域的地址,*表示所有
    response.setHeader('Access-Control-Allow-Origin','*')
    // 设置3s后响应
    response.send('hello')
})
// 监听端口,启动服务
app.listen(8000,() => {
    console.log("服务启动,监听8000端口中...");
})

前端:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ajax get请求</title>
    <style>
        #decorate{
            width: 200px;
            height: 100px;
            border: dotted 3px pink;
        }
    </style>
</head>
<body>
    <button id="btn">发送</button>
    <div id="decorate"></div>

    <script>
        let btn = document.getElementById('btn')
        let div = document.getElementById('decorate')
        btn.onclick = function(){
            const xhr = new XMLHttpRequest()
            xhr.open('get','http://127.0.0.1:8000/server)
            xhr.send()
            xhr.onreadystatechange = function(){
                if(xhr.readyState === 4){
                    if(xhr.status >=200 && xhr.status<300){
                        console.log(xhr.response); // 响应体
                        // 设置文本
                        div.innerHTML = xhr.response;
                    }
                }
            }
        }
    </script>
</body>
</html>

如果需要对所有的路由都解决跨域问题,那么可以写一个中间件,放在所有路由前面,如下

app.all('*', function (req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    res.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    next();
});

或者更简单点,引入一个别人已经写好的处理跨域请求的中间件,如下:
安装中间件

npm install cors

使用

app.use(cors())
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值