前端跨域(一):CORS
上周做了一个移动端表单提交的页面,其中涉及到了跨域问题,想来也是惭愧,因为之前一直都没有遇到过这个问题,因此都没有深入探索过,只是知道有哪几种方式,这次终于借这个机会可以把遗留的知识点补一补了。
1. CORS(Cross-Origin Resource Sharing,跨源资源共享)
【基本思想】:使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。
【实现方式】:
浏览器在发送请求时,检测到跨域时,会自动加上一个额外的 Origin 头部,其中包含请求页面的原信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给予响应。
Origin: http://www.nczonline.net
如果服务器认为这个请求可以接受,就在 Access-Control-Allow-Origin 头部中回发相同的原信息(如果是公共资源,可以回发“*”)。
Access-Control-Allow-Origin: http://www.nczonline.net
如果没有这个头部,或者有着头部但原信息不匹配,浏览器就会驳回请求。
注意:默认情况下,请求和响应都不包含 cookie 信息。
2. 跨域场景复原
为了模拟跨域,在自己的本地起了2个服务,一个采用 webpack 充当静态资源服务器(webpack 脚手架可参考:scaffoldsForFE),另一个用 Node 搭建,充当接受请求的服务器,分别给两个服务器分配了不同的端口号。
Client:http://localhost:8000
var oDiv = document.getElementById('content');
var xhr = new XMLHttpRequest();
xhr.onload = function() { // 响应接收完毕后将触发 onload 事件
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
oDiv.innerHTML = 'Request was success:' + xhr.responseText;
console.log('Request was success:', xhr.responseText);
} else {
oDiv.innerHTML = "Request was unsuccessful: " + xhr.status;
console.log("Request was unsuccessful: ", xhr.status);
}
}
}
xhr.open('get', 'http://localhost:8000', true); // 不跨域
// xhr.open('get', 'http://localhost:8888', true); // 跨域
xhr.send();
Server:http://localhost:8888
var http = require('http');
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('This is a server test page.');
res.end();
}).listen(8888);
当 Client 端向 http://localhost:8000 发请求时,不存在跨域,能够成功返回页面信息,此时的页面及其发请求的 Request Headers 如下:
当 Client 端向 http://localhost:8888 请求服务的时候,由于存在跨域问题,无法获得响应:
但是其请求的头部自动带上了 Origin 字段,而且由于是默认情况,没有带上 Cookie:
解决的方式是,在 Server 端响应的时候,在 Access-Control-Allow-Origin 头部中回发相应的原信息:
var http = require('http');
http.createServer(function(req, res) {
// 设置响应头部
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8000');
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('This is a server test page.');
res.end();
}).listen(8888);
再重新请求,成功获得响应信息,且请求没有带上 Cookie:
由于在跨域时,默认情况下是不允许客户端向服务器发送请求时带上 Cookie 的,那怎样才能带上 Cookie 呢?需要同时在客户端和服务端同时设置相应字段:
(1)客户端在请求中打开 withCredentials
属性,指定某个请求应该发送凭据:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
(2)服务端在响应头部中添加 Access-Control-Allow-Credentials
字段,且设为 true,表明服务器接受带凭据的请求:
res.setHeader('Access-Control-Allow-Credentials', true);
如果发送的是带凭据的请求,但服务器的响应中没有包含这个头部,那么浏览器就不会把响应交给 Javascript,则 responseText 是空字符串,status 的值为0,而且会调用 onerror() 事件处理程序。
cookie 是可以设置访问域的,在设置 cookie 的时候,设定了 cookie 的访问域名为一个顶级域名,则可以达到几个子域名共享 cookie 的效果,如腾讯网 www.qq.com 与微信网页版 wx.qq.com 共享了 pac_uid,关于前端存储的相关内容,可参考我之前在博客园写的博文:前端存储调研总结。
3. 模拟 GET 带参数 及 POST 跨域请求
i. GET 带参数跨域请求
Client 端:通过在URL后面加上查询参数
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.onload = function() { // 响应接收完毕后将触发 onload 事件
// 处理 xhr.responseText
}
xhr.open('get', 'http://localhost:8888?method=GET&name=Ruth', true);
xhr.send();
Server 端:处理 GET 请求
var http = require('http');
var url = require('url');
http.createServer(function(req, res) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8000');
res.setHeader('Access-Control-Allow-Credentials', true);
res.writeHead(200, {'Content-Type': 'text/plain'});
// 解析 url 参数
var params = url.parse(req.url, true).query;
res.write('请求类型:' + params.method);
res.write('<br />');
res.write('姓名:' + params.name);
res.end();
}).listen(8888);
ii. POST 跨域请求
不同于 JSONP,CORS 的好处就是可以让我们实现 POST 请求。
Client 端发送信息:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.onload = function() { // 响应接收完毕后将触发 onload 事件
// 处理 xhr.responseText
}
xhr.open('post', 'http://localhost:8888', true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); // 设置请求头
xhr.send('method=POST&name=Ruth');
Server 端处理请求:
var http = require('http');
var querystring = require('querystring');
http.createServer(function(req, res) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8000');
res.setHeader('Access-Control-Allow-Credentials', true);
res.writeHead(200, {'Content-Type': 'text/plain'});
var post = '';
// 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
req.on('data', function(chunk) {
post += chunk;
});
// 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回
req.on('end', function() {
post = querystring.parse(post);
res.write('请求类型:' + post.method);
res.write('<br/>')
res.write('姓名:' + post.name);
res.end();
});
}).listent(8888);
4. 参考资料
阮一峰-跨域资源共享 CORS 详解
AJAX POST&跨域 解决方案 - CORS
前端跨域的整理
前端跨域(一):CORS的更多相关文章
- 前端跨域(二):JSONP
上一篇文章 前端跨域(一):CORS 实现了跨域的一种解决方案,IE8 和其他浏览器分别通过 XDomainRequest 和 XHR 对象原生支持 CORS.这次我将补一补 Web 服务中也非常流行 ...
- JAVA解决前端跨域问题。
什么是跨域? 通俗来说,跨域按照我自己的想法来理解,是不同的域名之间的访问,就是跨域.不同浏览器,在对js文件进行解析是不同的,浏览器会默认阻止,所以 现在我来说下用java代码解决前端跨域问题. 用 ...
- 用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面
用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面 1.什么是跨域以及产生原因 跨域是指a页面想获取b页面资源,如果a.b页面的协议.域名.端口.子域名不同,或是a页面为ip地 ...
- Web前端学习笔记之前端跨域知识总结
0x00 前言 相信每一个前端er对于跨域这两个字都不会陌生,在实际项目中应用也是比较多的.但跨域方法的多种多样实在让人目不暇接.老规矩,碰到这种情况,就只能自己总结一篇博客,作为记录. 0x01 什 ...
- 前端跨域问题相关知识详解(原生js和jquery两种方法实现jsonp跨域)
1.同源策略 同源策略(Same origin policy),它是由Netscape提出的一个著名的安全策略.同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正 ...
- 跨域问题-cors
什么是跨域如大家所知,出于安全考虑,浏览器会限制脚本中发起的跨站请求.比如,使用 XMLHttpRequest 对象发起 HTTP 请求就必须遵守同源策略(same-origin policy). 具 ...
- 百万年薪python之路 -- 请求跨域和CORS协议详解
楔子 什么是同源策略 同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.当一个浏览器的两个tab ...
- java springmvc 前端 跨域问题
有个朋友在写扇贝插件的时候遇到了跨域问题.于是我对解决跨域问题的方式进行了一番探讨. 问题 API:查询单词URL: https://api.shanbay.com/bdc/search/?word= ...
- 搞懂:前端跨域问题JS解决跨域问题VUE代理解决跨域问题原理
什么是跨域 跨域:一个域下的文档或脚本试图去请求另一个域下的资源 广义的跨域包含一下内容: 1.资源跳转(链接跳转,重定向跳转,表单提交) 2.资源请求(内部的引用,脚本script,图片img,fr ...
随机推荐
- 关于分布式代码管理工具git
一.安装 Step1 进入官网https://www.git-scm.com/download/下载,然后安装,一直“下一步”即可 Step2 验证是否安装成功,在任意地方右键,菜单中含有Git ...
- k8s 部署rabbitmq单节点
apiVersion: extensions/v1beta1 kind: Deployment metadata: annotations: fabric8.io/iconUrl: https://r ...
- linux常用命令 grep命令
linux grep命令 Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配行打印出来 grep 全称 Grobal Regular Expression Pr ...
- ACCESS 查询重复记录
In (SELECT [全称] FROM [New14] As Tmp GROUP BY [全称],[账号],[银行] HAVING Count(*)>1 And [账号] = [New14] ...
- input输入框失去焦点,软键盘关闭后,滚动的页面无法恢复到原来位置
H5微信页面开发,软键盘弹起后,若原输入框被遮挡,页面整体将会上移,然而当输入框失焦,软键盘收起后,页面未恢复,导致弹框里的按钮响应区域错位. 解决方案:给输入框(或select选择框)添加失去焦点的 ...
- [Leetcode 72]编辑距离 Edit Distance
[题目] Given two words word1 and word2, find the minimum number of operations required to convert word ...
- 【基于微信小程序的社区电商平台】需求分析心得——小豆芽
一.项目内容 基于微信小程序,做一个社区电商平台,抓住社区电商的特点,做出特色,与微信集成,实现商品的个性化发布,以及个性化营销. 个性化发布:用户可以在应用上直接发布自己的商品,通过搜索心愿单可以查 ...
- Python 实现清屏
使用Python的IDLE到某个程序节点时,需要清屏以提高清晰度. 但IDLE本身并没有这个功能,我们可以通过扩展来实现类似于Ctrl + L的清屏 资料来自于百度经验的 BinnLZeng 先制作一 ...
- 下载、安装 SQL server 2012,一步一步教你安装、激活sql server2012数据库 ,附有数据库安装包
一. 准备阶段:下载2012 SQl server数据库安装包. 链接如下: 文件名:sql2012.zip 百度云链接:https://pan.baidu.com/s/1-fw1dCVbfU1bKM ...
- 远程连接SqlServer 数据库时提示 "在与SQL Server 建立连接时出现与网络相关的或特定实例的错误" 解决方法
前言 由于在之前的职业生涯中, 无论是数据库还是开发环境, 都是前人弄好的,自己只管使用就好啦.并不知安装过程中会出现各种各样的错.最近接触服务器之后,开发环境以及配置各方面都是从头到脚开始安装到配置 ...