You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
consthttp=require('http')constserver=http.createServer((request,response)=>{if(request.url==='/'){if(request.method==='GET'){response.writeHead(200,{'Access-Control-Allow-Origin': 'http://localhost:3000'})response.end("{name:'chen',password:'test'}")}if(request.method==='POST'){response.writeHead(200,{'Access-Control-Allow-Origin': 'http://localhost:3000','Access-Control-Allow-Credentials': true,// 此处设置的cookie还是http://localhost:4000的而非http://localhost:3000,因为后端也不能跨域写cookie(nginx反向代理可以实现),// 但只要http://localhost:4000中写入一次cookie认证,后面的跨域接口都能从http://localhost:4000中获取cookie,从而实现所有的接口都能跨域访问'Set-Cookie': 'l=a123456;Path=/;Domain=http://localhost:3000;HttpOnly'// HttpOnly的作用是让js无法读取cookie})response.end('true')}}response.end('false')})server.listen(4000,()=>{console.log('the server is running at http://localhost:4000')})
letexpress=require('express')letapp=express();letwhiteList=['http://localhost:3000']app.use(function(req,res,next){letorigin=req.headers.originif(whiteList.includes(origin)){// 设置哪个源可以访问我res.setHeader('Access-Control-Allow-Origin',origin)// 允许携带哪个头访问我res.setHeader('Access-Control-Allow-Headers','name')// 允许哪个方法访问我res.setHeader('Access-Control-Allow-Methods','PUT')// 允许携带cookieres.setHeader('Access-Control-Allow-Credentials',true)// 预检的存活时间res.setHeader('Access-Control-Max-Age',6)// 允许返回的头res.setHeader('Access-Control-Expose-Headers','name')if(req.method==='OPTIONS'){// res.end();}}next();})app.put('/getData',function(req,res){console.log(req.headers)res.setHeader('name','jw')res.end('i don\'t love you')})app.get('/getData',function(req,res){console.log(req.headers)res.end('i love u')})app.use(express.static(__dirname))app.listen(4000,()=>{console.log('serve at 4000')})
// server.jsvarhttp=require('http');varserver=http.createServer();varqs=require('querystring');server.on('request',function(req,res){varparams=qs.parse(req.url.substring(2));// 向前台写cookieres.writeHead(200,{'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'// HttpOnly:脚本无法读取});res.write(JSON.stringify(params));res.end();});server.listen('8080');console.log('Server is running at port 8080...');
varexpress=require('express')varproxy=require('http-proxy-middleware')varapp=express();app.use('/',proxy({target: 'http://www.domain2.com:8080',changeOrigin: true,// 修改响应头信息,实现跨域并允许带cookieonProxyReq: function(proxyRes,req,res){res.setHeader('Access-Control-Allow-Origin','http://www.domain1.com');res.setHeader('Access-Control-Allow-Credentials','true');},// 修改响应中的cookie域cookieDomainRewrite: 'www.domain1.com'// false 为不修改}))app.listen(81,()=>{console.log('Proxy server is running at port 81...')})
后台接口:
varexpress=require('express')varapp=express();varqs=require('querystring')app.use(function(req,res,next){varparams=qs.parse(req.url.substring(2));res.setHeader('Set-Cookie','l=a123456;Path=/;Domain=www.domain2.com;HttpOnly')res.write(JSON.stringify(params));res.end();})app.listen(8080,()=>{console.log('Server is running at port 8080...')})
什么是跨域?
浏览器的同源策略
在解释跨域的概念之前,先让我们来了解下浏览器的同源策略,这也是为什么会有跨域的由来。
同源策略是一项约定,是浏览器的行为,限制了从同一个源下的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
所谓同源是指
协议
+域名
+端口
三者都相同,不满足这个条件即为非同源,即使两个不同域名指向同一IP地址。 当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。 不同域之间相互请求资源,就算作跨域
。同源策略限制的内容:
注意:有三个标签是允许跨域加载资源的:
<img src=XXX>
<link href=XXX>
<script src=XXX>
总结一下就是: 同源策略是浏览器的一种安全行为,是为了阻止一个域下的文档或脚本读取另一个域下的资源污染自身,所以拦截了响应。 这也是为什么表单提交可以跨域(因为没有获取新的内容)。
常用的解决方案
1.JSONP (json with padding)
1) 原理
利用
<script>
标签不受跨域限制,将回调函数名作为参数附带在请求中,服务器接受到请求后,进行特殊处理:把接收到的函数名和需要给它的数据拼接成一个字符串返回,客户端会调用相应声明的函数,对返回的数据进行处理。2) 示例
封装jsonp请求
上述代码向
http://localhost:3000/say?wd=Iloveyou&cb=show
发起请求,服务器返回show('我不爱你')
,因而前台将会调用show方法。3) 优缺点
简单兼容性好,解决主流浏览器跨域数据访问。缺点是
仅支持GET
方法,且需要服务器做支持才能实现。2.CORS
CORS(cross-origin resource share)跨域资源共享 只是在 HTTP 协议内部,新增了若干个 header字段 ,来制定
跨域资源共享
的实现规则。目前所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。浏览器会自动进行 CORS 通信,实现 CORS 通信的关键在于后端。只要后端实现了 CORS,就实现了跨域。根据浏览器发送的请求可以分为两种情况。
1) 简单请求
若请求满足所有下述条件,则该请求可视为“简单请求”:
对于简单请求,只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。如果想实现当前页cookie的写入,可参考nginx反向代理中设置proxy_cookie_domain 和 NodeJs中间件代理中cookieDomainRewrite参数的设置。
2) 复杂请求
不符合以上条件的请求就肯定是复杂请求了。
复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为
预检
请求,该请求是option
方法的,通过该请求来知道服务端是否允许跨域请求。复杂请求例子:
上述代码由http://localhost:3000/index.html向http://localhost:4000/跨域请求,正如我们上面所说的,后端是实现 CORS 通信的关键,需要对引起跨域的因素在OPTION中进行相应的处理。
3.ngnix反向代理
1) 跨域原理
同源策略是浏览器的安全策略,不是HTTP协议的一部分。而服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,因此也就不存在跨越问题。
2) 实现思路
通过
nginx
配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。3) 示例代码
nginx相关配置:
前端代码:
Nodejs后台:
4.Nodejs中间件代理
1)原理
原理和上面的nginx大致相同,都是利用服务器之间无需遵守同源策略,通过一个代理服务器,实现请求的转发以及设置CORS。
2) 实现思路
node + express + http-proxy-middleware 搭建proxy服务器
3) 示例代码
前端代码:
中间件:
后台接口:
参考资料
The text was updated successfully, but these errors were encountered: