用express实现CORS跨域(上-简单请求)
今天遇到了一个跨域请求登录验证的问题。所以有了尝试跨域的机会。
具体情景是,有一个登录界面写在名叫cas的站点上,但是相关的登录验证的后台接口是写在名叫earth的站点。
首先的反应是使用jsonp,但是jsonp只能get请求,而且一旦跨域会有权限问题(这个下面会说),更主要的是jsonp那种类似hack的写法总让我觉得别扭。当然最主要的是后台用stringMVC已经实现了CORS。
CORS是一种跨域资源共享的方式,和ajax实际上是没什么区别的,相对应的RESTFUL方法们都是可以的,实现方式上是有区别的。
这次就先总结下比较简单的,用GET发一个邮箱地址,让后台验证这个邮箱是否可用,返回true或者false。
首先先写一个客户端,这个客户端是用webstorm默认的方式起的,域名应该是localhost:63342
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="cors">send cors</button> </body> <script> var cors=document.querySelector('#cors'); cors.onclick=function () { var xhr=new XMLHttpRequest(); xhr.open('GET','http://localhost:3001/getName',true); xhr.withCredentials=true; xhr.onload=function (data) { console.log(data); }; xhr.send(null); } </script> </html>
这个页面就是点击一个按钮向3001端口发送一个GET请求,可以看到除了xhr.withCredentials=true;以外和ajax没什么区别,CORS基本上就是个服务端技术。另外提一句,在高程三上说需要在请求头上写一句Origin:XXXX来告诉服务端你的源信息,但是实际上我测试的时候发现即使不写,浏览器也会自动把这句加到请求头里。
var express=require('express');
var url=require('url');
var app=express();
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:63342');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Credentials','true');
next();
};
app.use(allowCrossDomain);
app.get('/checkEmail',function (req,res,next) {
var queryValue=url.parse(req.url).query;
if(queryValue==='fortunewheel@sina.com'){
res.send(true);
}else {
res.send(false);
}
});
app.listen(3001);
可以看到比较明显的区别就是多了一个allowCrossDomain的中间件,这个中间件的作用就是向响应头里写一些东西。
为什么是响应头?下面是我的一点理解,不对欢迎指正:
跨域请求需要做处理的原因是同源策略,即协议、域名和端口必须完全相同才能发起请求。而同源策略实际上是浏览器行为,因为不做限制的跨域是比较危险的,所以各个浏览器都会做跨域限制。对于CORS会向服务端发送一个预请求,服务端写回响应头。浏览器发现预请求的响应头是允许自己发送请求的才会发送真正的请求。
下面这一句就是告诉什么站点是被允许的
res.header('Access-Control-Allow-Origin', 'http://localhost:63342');
浏览器就会知道服务器是允许这个站点进行跨域访问的。其实,这就是一个白名单机制。
其他的三条是什么意思百度下就好。稍微提一句,建议在客户端写上xhr.withCredentials=true; 对应的服务端也要加上对应的响应头。不过这样写,Access-Control-Allow-Origin就不能写*来允许所有站点请求,在实际工程上也很少允许所有站点。而这也是jsonp不好的地方,如果向设定请求权限要考虑使用其他方法,不如CORS简便。
当然,上面说的都是简单请求的CORS。HEAD GET POST方法下,使用某些请求头(嗯,传个json是肯定没问题)都是简单请求。
复杂请求的机制和简单请求不太一样,有空写写个下篇详细说明下。