跨域

68次阅读

共计 4576 个字符,预计需要花费 12 分钟才能阅读完成。

前端跨域问题我想很多同学遇到过,或者是刚刚请求数据成功, 然而转眼之后就会报错
XMLHttpRequest cannot load http://www.server.com/server…. No ‘Access-Control-Allow-Origin’ header is present on the requested resource.Origin ‘http://www.client.com’ is therefore not allowed access.
我不知道大家有没有遇到过反正我是遇到过,不管在什么时候你都有可能遇到跨域

跨域是什么?

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。

为什么会产生跨域?

产生跨域的主要原因是因为同源策略,什么是同源策略呢?我们来看下面的解释

同源策略 /SOP(Same origin policy)是一种约定,由 Netscape 公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到 XSS、CSFR 等攻击。所谓同源是指 ” 协议 + 域名 + 端口 ” 三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源,看看下面的产生跨域的场景你就会明白同源策略的含义。
那么有的人会问了,同源策略会产生跨域为什么还要存在呢?平常我们访问网站的时候都是一个地址对应相同的内容,如果同源策略不存在网站的 dom 很有可能被钓鱼网站复制,那样你就会上当。
那有的人又问了有了同源策略就安全吗?不是有了它就安全是因为同源策略是基础的安全机制,面对强大的攻击还是需要强大的攻防的

跨域场景

url 说明 是否可以通信
http://www.kuayu.com/img.jpg 同一域名,不同文件,不同路径 可以
http://www.kuayu.com/img2.jpg 同一域名,不同文件,不同路径 可以
url 说明 是否可以通信
http://www.kuayu.com:6666/img.jpg 同一域名,不同端口 不可以
http://www.kuayu.com/img2.jpg 同一域名,不同端口 不可以
url 说明 是否可以通信
https://www.kuayu.com/img.jpg 同一域名,不同协议 不可以
url 说明 是否可以通信
http://www.kuayu.com/img.jpg 主域相同,子域不同 不可以
http://kuayu11.com/img2.jpg 主域相同,子域不同 不可以

跨域的解决办法

  1. jsonp

    Jsonp(JSON with Padding) 是 json 的一种 ” 使用模式 ”,可以让网页从别的域名(网站)那获取资料,即跨域读取数据。
    为什么我们从不同的域(网站)访问数据需要一个特殊的技术 (JSONP) 呢?这是因为同源策略。
    同源策略,它是由 Netscape 提出的一个著名的安全策略,现在所有支持 JavaScript
    的浏览器都会使用这个策略。同源策略上面咱们已经简单的价绍过了,详细请看上面

    首先我们先设置 script 标签,一个简单的 jsonp 实现,其实就是拼接 url,然后将动态添加一个 script 元素到头部,我来看下面菜鸟教程给与的客户端例子

       <!DOCTYPE html>
       <html>
       <head>
           <meta charset="utf-8">
           <title>JSONP 实例 </title>
       </head>
       <body>
       <div id="divCustomers"></div>
       <script type="text/javascript">
           // 创建函数
           function callbackFunction(result, methodName)
           {
               // 声明 ul 标签
               var html = '<ul>';
               // 循环创建 li 插入 ul
               for(var i = 0; i < result.length; i++)
               {html += '<li>' + result[i] + '</li>';
               }
               html += '</ul>';
               // 写入 html
               document.getElementById('divCustomers').innerHTML = html;
           }
       </script>
       // 使用函数
       <script type="text/javascript" src="http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction"></script>
       </body>
       </html>

    我们再来封装一下简单的 jsonp 函数完整的代码如下面

        <!DOCTYPE html>
           <html>
           <head>
               <meta charset="utf-8">
               <title>JSONP 实例 </title>
           </head>
           <body>
           <div id="divCustomers"></div>
           <script type="text/javascript">
               function jsonp(req){
                   // 创建 script 的标签
                   var script = document.createElement('script');
                   // 拼接 url
                   var url = req.url + '?callback=' + req.callback.name;
                   // 赋值 url
                   script.src = url;
                   // 放入头部
                   document.getElementsByTagName('head')[0].appendChild(script);
               }
           </script>
           </body>
           </html>
     上面的代码使用方式和咱们菜鸟教程生成的方式是一样的

后台解决跨域

一般有两种解决方法

1. 后台返回的数据格式改成 jsonp 的形式

2. 后台 response 添加 header,response.setHeader("Access-Control-Allow-Origin", "*");
"Access-Control-Allow-Origin", "*" 表示所有网站都可以访问
或者可以指定某个具体域名访问 response.setHeader("Access-Control-Allow-Origin", "url")

我们来看看后台代码 node + koa 的实现,我们可以通过设置 header 的 Access-Control-Allow-Origin 就像是我们设置的 token,设置的 json 格式或是其它格式啊,当然下面的代码是通过使用 koa-cors 插件进行的解决跨域问题。

var koa = require('koa');
var route = require('koa-route');
var cors = require('koa-cors');
var app = koa();

app.use(cors());

app.use(route.get('/', function() {this.body = { msg: 'Hello World!'};
}));
app.listen(3000)

其实这一切都归根揭底为 cors,那么它是什么呢? 它为什么可以解决跨域的问题呢?那我们具体来看看它到底是什么

cros:跨域资源共享 浏览器将 CORS 请求分成两类:简单请求(simple request)和非简单请求(not-so-simple
request),咱们在这里只说一下简单的请求方式:

请求方法是以下三种方法之一:

HEAD
GET
POST

HTTP 的头信息不超出以下几种字段:

Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain

Access-Control-Allow-Origin

该字段是必须的。它的值要么是请求时 Origin 字段的值,要么是一个 *,表示接受任意域名的请求。

Access-Control-Allow-Credentials

值是一个布尔值,表示是否允许发送 Cookie。默认情况下,Cookie 不包括在 CORS 请求之中。设为 true,即表示服务器明确许可,Cookie 可以包含在请求中,一起发给服务器。这个值也只能设为 true,如果服务器不要浏览器发送 Cookie,删除该字段即可

vue 解决跨域方案

我们可以在 vue-cli 配置文件里面设置一个代理,跨域的方法有很多,通常需要后台来进行配置。
我们可以直接通过 node.js 代理服务器来实现跨域请求。

接下来我们可以通过 vue 项目中 config 文件夹下的 index.js 配置文件

dev: {
    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {},

    // Various Dev Server settings
    host: '0.0.0.0', // can be overwritten by process.env.HOST
    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: false,
    errorOverlay: true,
    notifyOnErrors: true,
    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
    .......
    ...
  }

上面是我从 vue 项目中拿出来的代码供大家便于寻找, 接下来我们需要新建一个 js 文件,名为 proxy.js 配置代码如下:

module.exports = {
  proxy: {
        '/api': {    // 将 www.qj.com 映射 /apiUrl
            target: 'https://www.qj.com',  // 接口域名
            secure: false,  // 如果是 https 接口,需要配置这个参数
            changeOrigin: true,  // 是否跨域
            pathRewrite: {'^/api': '' // 路径重写}              
        }
  }
}

这把我们需要把 proxy.js 引入到 config 文件夹下的 index.js 中,var proxy = require('./proxy.js'), 然后将 proxyTable: proxy.proxy 插入到我们的 dev 对象中进行跨域的使用,我们这时候如果设置完了,跨域还是没有解决怎么办,有时候还得需要更改咱们本地的 hosts 文件以达到我们解决跨域的目的

总结

其实在我开发的经历中遇到跨域的事情还是较少的,一般遇到跨域的时候,基本上都是又后台来处理,以前也会遇到但是使用 jsonp 的时候还是比较少的,以及上面我们提到的 vue-cli 的设置解决跨域的问题,我们看到是直接设置 webpack 的方式来解决,由于 vue 开发比较多,所以还是比较关注 vue 的解决方法,有的时候还碰到过比如我们开发 web 页面和小程序,在小程序请求都没有 went,但是到 web 也会造成跨域问题,所以我们只需设置前台解决跨域问题就行,或者更安全的方式直接让后台一次性解决也免得不小心手机端也跨域了呢

参考资料
正确面对跨域,别慌
菜鸟教程
jsonp 跨域请求详解——从繁至简
阮一峰 cros

正文完
 0

跨域

68次阅读

共计 483 个字符,预计需要花费 2 分钟才能阅读完成。

什么是跨域
一般来说,当一个请求 url 的协议、域名、端口三者之间任意一个与当前页面地址不同即为跨域。
原因
跨域产生的条件:浏览器同源策略限制
浏览器是从两个方面去做这个同源策略的:

DOM 同源策略。禁止对不同源的页面的 DOM 进行操作,主要包括 iframe、canvas 之类的。不同源的 iframe 禁止数据交互的,含有不同源数据的 canvas 会受到污染而无法进行操作。
XmlHttpRequest 同源策略。简单来说就禁止不同源的 AJAX 请求,主要用来防止 CSRF 攻击。

同源策略
同源是指“三个相同”:

协议相同
域名相同
端口相同

同源策略的限制

存储在浏览器中的数据,如 localStroage、Cookie 和 IndexedDB 不能通过脚本跨域访问
不能通过脚本操作不同域下的 DOM
不能通过 ajax 请求不同域的数据

在浏览器中,script,img、iframe、link 等标签都可以加载跨域资源,而不受同源限制,但浏览器限制了 JavaScript 的权限使其不能读、写加载的内容。
跨域的解决方案
Cookie
JSONP
CORS
window.domain
window.name
WebSocket

正文完
 0

跨域

69次阅读

共计 2714 个字符,预计需要花费 7 分钟才能阅读完成。

前端跨域的各种知识点
每次复习基础知识的时候,都会看一些有关跨域的知识点。但在工作中从来没有用到过。恰巧,前几天官网的同事让我请求他们的接口,并指明需要用到 jsonp。说实话,当时我是有一点懵的。(内心 os:jsonp 到底应该咋用啊)。为了下次再遇到这种情况不至于很尴尬。今天,就来总结一下跨域的基本知识点。
1. 为什么会发生跨域这种情况呢?
我们通常都是用 ajax 进行网络请求的。ajax 的技术核心是 XMLHttpRequest 对象(简称 XHR 对象)。(既然都提到 ajax 了,不如复习下吧)
1.1 XHR 的用法
1.1.1 同步请求
var xhr = createXHR()
xhr.open(‘get’, ‘example.php’, false) // 参数:请求方式、请求地址、是否异步
xhr.send(null)
if((xhr.status > 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText)
} else {
alert(‘error’)
}
open()方法并不会真正的发送请求。而知识启动一个请求以备发送。send()方法接收一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入 null。调用 send()方法之后,请求就会被分派到服务器。在收到响应后,响应会自动填充 XHR 对象的属性。
responseText:响应的主体被返回的文本 responseXML:如果响应的内容类型是 ”text/xml” 或 ”application/xml”,这个属性中将保存着响应数据的 XML DOM 文档。status:响应的 HTTP 状态。(200:请求成功。304:请求的资源没有被修改。302:重定向。404:找不到路径。500:服务器报错) statusText:HTTP 状态的说明
1.1.2 异步请求异步请求,可以检测 XHR 的 readyState 属性。该属性表示请求 / 响应过程的当前活动阶段。
var xhr = createXHR();
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if((xhr.status > 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText)
} else {
alert(‘error’)
}
}
}
xhr.open(‘get’, ‘example.php’, true)
xhr.send(null)
2. 什么是跨域
跨域:同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。同源指:协议、域名、端口号必须一致。同源策略控制了不同源之间的交互,例如在使用 XMLHttpRequest 或 标签时则会受到同源策略的约束。这些交互通常分为三类:

通常允许跨域写操作(Cross-origin writes)。例如链接(links),重定向以及表单提交。特定少数的 HTTP 请求需要添加 preflight。
通常允许跨域资源嵌入(Cross-origin embedding)。
通常不允许跨域读操作(Cross-origin reads)。但常可以通过内嵌资源来巧妙的进行读取访问。例如可以读取嵌入图片的高度和宽度,调用内嵌脚本的方法,或 availability of an embedded resource。

下面为允许跨域资源嵌入的示例,即一些不受同源策略影响的标签示例:

<script src=”…”></script> 标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到。
<link rel=”stylesheet” href=”…”> 标签嵌入 CSS。由于 CSS 的松散的语法规则,CSS 的跨域需要一个设置正确的 Content-Type 消息头。不同浏览器有不同的限制:IE, Firefox, Chrome, Safari 和 Opera。
<img> 嵌入图片。支持的图片格式包括 PNG,JPEG,GIF,BMP,SVG
<video> 和 <audio> 嵌入多媒体资源。
<object>, <embed> 和 <applet> 的插件。
@font-face 引入的字体。一些浏览器允许跨域字体(cross-origin fonts),一些需要同源字体(same-origin fonts)。
<frame> 和 <iframe> 载入的任何资源。站点可以使用 X -Frame-Options 消息头来阻止这种形式的跨域交互。

3. 跨域的解决方法
下面是比较常用的解决跨域的方法。3.1.1 jsonp
jsonp 是利用动态添加 script 标签的形式,来进行跨域访问。因为 script 标签和 img 标签都有能力不受限制的从其他域加载资源。
jsonp 由两部分组成:回调函数和数据(callback({name: ‘xuying’}))
如果其他域不是特别安全,如果用 jsonp 进行跨域,则会有一些安全隐患。其次,要确定 jsonp 请求是否失败也并不容易。
3.1.2 CORS(跨域资源共享)
跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。
比如一个简单的 get 或者 post 请求,他没有自定义的头部,而主体内容应该是 text/plain。在发送该请求时,需要给它附加一个额外的 origin 头部,其中包含请求页面的源信息 (Origin: http://www.nnn.net), 如果服务 …,就在 Access-Control-Allow-Origin 头部中回发相同的源信息(如果是公共资源,可以回发 ’*’)(Access-Control-Allow-Origin: http://www.nnn.net) 如果没有这个头部,或者有这个头部但源信息不匹配,浏览器都会驳回请求。ps:请求和响应都不包含 cookie 信息。
其他有关跨域的知识点,可以看这两篇博客:掘金:https://juejin.im/post/5b5ff1…github:https://github.com/Nealyang/Y…

正文完
 0