服务端跨域处理原理以及处理

服务端跨域处理原理以及处理

背景

随着CROS标准的推广,跨域成了每个服务器开发者必须处理的问题,网上关于如何解决跨域问题的文章数不胜数,但是能用的少之又少,不少文章作者都不清楚跨域原理,不知从哪里抄来一字半句发现有效果就匆匆发表,误导了不知多少人。

其实处理跨域的原理并不复杂,本文会介绍处理跨域的原理并给出python实现。

跨域标准

CROS标准是W3C定义的新标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

讲解CROS标准的文章推荐阮一峰的《跨域资源共享 CORS 详解》,讲的比较清楚明了,本文不再赘述CORS标准,只讲服务端的处理

CORS标准需要浏览器支持,浏览器会自动按照CORS标准发出请求,服务器需要按照CROS标准给出对应的回复,否则浏览器拒绝继续HTTP请求。

新版本的浏览器基本都强制开启了跨域请求,所以除非你能限制浏览器,不然都免不了跨域这一关。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨域通信。

跨域也可以从浏览器关闭,但是目前都需要在浏览器启动传入参数或者修改一些内部配置,没有办法在前端代码里关闭。

所以网上所有说在web代码里处理跨域的都是在扯蛋,跨域请求必须由服务器作出处理。而所有说在服务端关闭跨域的也是在扯蛋,只能从浏览器端关闭跨域。

跨域处理

跨域处理分两种,简单请求和非简单请求。

怎么分辨是不是简单请求呢?其实很简单,同时满足以下全部条件的就是简单请求:

  • HTTP请求方法只能是以下几种方法之一:
    • HEAD
    • GET
    • POST
  • HTTP请求的头信息只有以下字段:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type
  • 如果HTTP请求的头信息有Content-TypeContent-Type值只能是以下几种之一:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

简单请求

浏览器在对一个url发起简单跨域请求时会在HTTP请求头中设置一个Origin字段,表示浏览器发起请求的来源地址。

服务器需要检查这个来源是否合法,如果合法的话,服务除了需要正常处理业务以外,还需要在HTTP回复的响应头中设置如下字段:

  • Access-Control-Allow-Origin
    • 值和请求头中的Origin字段值一致
  • Access-Control-Allow-Credentials
    • 值一般设为字符串类型的true,表示是否允许发送Cookie

非简单请求

非简单请求的处理除了要完成上述对于简单请求的处理之外,还需要一些额外的处理。

浏览器在对一个url发起跨域非简单请求时首先会发出一个相同url的OPTIONS方法的请求,一般我们称之为preflight。然后根据preflight请求的结果再进行实际的请求发送。

浏览器会在preflight的HTTP请求头中设置一个Access-Control-Request-Method字段,用来表示本来实际发起的请求是什么方法。

如果实际的请求头中包含自自定义的字段,那么浏览器在还会在preflight的HTTP请求头中设置一个Access-Control-Request-Headers字段,用来表示实际发起的请求头中将要包含的字段。

对于preflight的处理,服务器此时应返回200,并先对此请求进行简单请求的处理,然后再返回的请求头中设置如下字段:

  • Access-Control-Allow-Methods

    • 此字段表示服务器针对此url允许哪些方法的请求,一般来说,值可以设为请求头中的Access-Control-Request-Method字段的值。但是最好每次都全部设为GET,POST,PUT,DELETE,OPTIONS,这样可以避免浏览器针对每种方法都发起preflight,提升性能。
  • Access-Control-Allow-Headers

    • 此字段表示服务器允许接收的请求头的字段,如果浏览器的请求头中有Access-Control-Request-Headers,则将值设置为和请求头中Access-Control-Request-Headers字段的值一致。否则设为字符串类型的*

当浏览器完成了preflight请求并且服务器给出的响应都正确,浏览器才会发起真正的跨域非简单请求。此时的处理就比较简单了。此时浏览器应该先对此请求进行简单请求的处理,然后按照preflight响应头中关于Access-Control-Allow-Headers的处理规则进行处理即可。

python-bottle实现

通常来说,一个现代的、成熟的服务器框架应该可以按照配置自己处理CROS,但是当框架没有提供时,就需要我们按照上文规范自己处理。

这里给出使用python的bottle框架的跨域处理。其他的框架、语言也可以参考以下实现

响应头处理

首先针对所有的请求,使用hook做统一的响应头处理

@ app.hook('after_request')
def enable_cors():

    if 'Origin' in request.headers:

        origin = request.headers['Origin']

        response.headers['Access-Control-Allow-Origin'] = origin

        response.headers['Access-Control-Allow-Credentials'] = 'true'

    if 'Access-Control-Request-Headers' in request.headers:

        response.headers['Access-Control-Allow-Headers'] = request.headers['Access-Control-Request-Headers']

    else:

        response.headers['Access-Control-Allow-Headers'] = '*'

OPTION请求处理

然后针对所有OPTION请求做处理

@ app.route(urlPrefix+'/<n:re:.+>', method='OPTIONS')
def options(n):

    response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE,OPTIONS'
    return ''
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值