龙空技术网

前端跨域请求及解决方案

肆零三工作室 1004

前言:

如今大家对“ajaxhtml传递参数乱码问题”大体比较注意,看官们都需要了解一些“ajaxhtml传递参数乱码问题”的相关知识。那么小编也在网摘上网罗了一些有关“ajaxhtml传递参数乱码问题””的相关内容,希望你们能喜欢,小伙伴们一起来了解一下吧!

前言

本期文章的视频内容可以去 B 站搜索看,视频内容有完整的分析和演示

在 BS 架构的项目中以及前端开发编码过程中有可能会遇到跨域的问题,而跨域问题随着现代 web 开发很多项目采用前后端分离的方式进行分工合作再一次成为前端开发过程中都会遇到问题。曾经有一段时间 JSONP 的一度成为很多跨域问题的解决方案。在个人印象中曾经有一段时期各个公司关注于建站建官网进行 SEO,那个时候很多开发人员都会在前端粘贴一段脚本用来监控对网站的请求,那个时候跨域问题开始进入我个人的视野。后来随着 Vue、Angular、React 的兴起刮起了前端开发变革的风,前后分离的开发方式让跨域问题再一次成为需要面对的问题。

所谓跨域问题实际上就是浏览器的一个非常核心的安全策略,有很多方法可以来解决这个问题,各个方法使用场景各不相同。在项目中有有使用过几个解决方案,在这里做归纳总结

什么是跨域请求

在前端开发编码过程中,常见的 html 标签例如:a、form、img、script、link、iframe以及 Ajax 操作都可以指向一个资源地址或者说可以发起对一个资源的请求,那么这里所说的请求就存在同域请求还是跨域请求。

所谓跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一致(这里所有的域是协议、域名和端口号的合集,同域就是所协议、域名和端口号均相同,任何一个不同都是跨域)。

常见的跨域场景有:

常见的跨域场景

同源策略(same-origin pllicy)

同源策略是由 Netscape 提出的一个著名的安全策略,它是浏览器最基本最核心的安全功能。如果缺少了同源策略,则浏览器的正常功能都会受到影响,可以说 web 是构建在同源策略基础上的,浏览器是针对同源策略的一种实现。

同源策略是浏览器的行为,是为了保护本地数据不被 Javascript 代码获取回来的数据污染,因此拦截的是客户端发出请求后回来的数据接收,即请求发送了,服务器响应了,但无法被浏览器接收执行,在现代浏览器中违反同源策略的跨域请求会在控制台直接报错。

chrome控制台报错信息

同源策略的具体表现:

DOM 层面的同源策略,限制了来自不同源的Document对象或者 JS 脚本对当前Document对象的读取或设置某些属性Cookie 和 XMLHttpRequest 层面的同源策略,默认情况下禁止 Ajax 直接进行跨域请求(请求可以发起,但接收结果等操作被浏览器拦截并在控制台报错),cookie 层面数据默认不能跨域访问特定 HTML 标签的的策略,a、form、img、script、link、iframe等这些有src属性的标签可以对资源跨域访问和执行

为什么会有这些限制

同源策略是浏览器最核心基础的一个安全策略,是浏览器基于安全的需要来进行的限制。常见的CSRF、XSS攻击都与之有关联。在这里就不做介绍,有兴趣的读者可以自行去搜索了解下这些攻击的原理

跨域请求为什么会出现在前端开发中?

既然同源策略是浏览器的核心基础安全策略,那为什么我们在进行前端开发特别是 Ajax 调用时还要进行跨域请求呢?同源策略是用来防御来自非法的攻击,但我们不能因为防御非法的攻击就将所有的跨域都拦截掉。

在现代前端开发中,我们经常需要调用第三方的服务接口(例如 mock server、fake api),随着专业化分工的出现有很多专业的信息服务提供商为前端开发者提供各类接口,这种情况下就需要进行跨域请求(这类前端接口服务很多是采用的 cors 方式来解决跨域问题的,下文会详细介绍)。

还有一类情况是在前后端分离的项目中,前端后端分属于不同的服务跨域问题在采用这种架构的时候就存在。而且现在很多项目都采用这种前后分离的方式,这类项目很多是会采用反向代理的方式来解决跨域问题。

Ajax 跨域请求如何实现

这里所说的跨域请求解决方案主要是针对 Ajax 请求

修改浏览器的安全设置(不推荐)

既然是浏览器的安全策略,那么最简单粗暴的方法就是禁用这个策略。这种操作很危险,不推荐使用。在此也不做具体的介绍,在跨域问题刚出来的时候有人采用这种方法,目前已很少有人采用。

JSONP

JSONP(JSON with Padding)是 JSON 的一种使用模式,可用于解决主流浏览器的跨域数据访问问题,在早两三年前端解决跨域问题中经常出现这类解决方案。

JSONP 的原理就是,Ajax 存在跨域安全问题但是 script 标签是不存在这类问题的,于是乎就有人根据这个特性做文章找解决方案。

remote.com/remote.js

remoteFunction('remote)

index.html

<script src="" type="text/javascript"></script><script>remoteFunction()</script>

我们都知道这种方式是可以成功的,因此进一步改造:

remote.com/remote.js

let data = { code: 200, msg: "data from remote"};localFunction(data);

index.html

<script>localFunction(data) { console.log(data)}</script><script src="" type="text/javascript"></script>

通过这一步的改造就可以发现我们的本地函数的参数是来自于远程服务,在远程 remote.js 根据业务逻辑传递参数到本地函数进行的调用。

于是更进一步,将代码写死的 remote.js 进行动态的生成,我们以后台 PHP 语言为例:

remote.php

<?php//通过设置content-type能够指明返回的内容类型header('Contetn-type:application/json');$callbackFunction = htmlspecialchars($_GET['callback']);$data = 'data from remote';echo $callbackFunction.'('.$data.')';

index.html

<script type="text/javascript"> localFunction = function(data) { console.log(data); };</script><script src="" type="text/javascript"></script>

这种实现方式就是 JSONP 的简单实现,JSONP 的核心理念就是利用 script 可以进行跨域请求,通过跨域请求将业务处理逻辑的回调函数通过 url 参数的形式发给远程请求,远程请求通过数据库调用获取到前端需要的数据后,将发送过来的回掉函数以及数据参数进行拼装,生成一段可执行的 JavaScript(json)代码,这样当这次请求完成后,对应的业务处理函数也就对应的执行了。

JSONP 有其天然的缺陷,因为是通过 script 的 src 进行的资源请求,所以都是 GET 方式,其他的 POST、PUT、DELETE 并不支持。这种采用这种解决方式越来越少。

跨域资源共享 CORS(Cross-Origin Resource Sharing)

CORS 是一个新的 W3C 标准,它新增的一组 HTTP 首部字段允许服务器其声明哪些来源请求有权限访问哪些资源,换言之它允许浏览器向其声明了 CORS 的站进行跨域请求。

这种方式最主要的特点就是会在响应的 HTTP 首部增加 Access-Control-Allow-Origin 等信息,从而判定哪些资源站可以进行跨域请求,还有几个其他相关的 HTTP 首部进行更加精细化的控制,最主要的还是 Access-Control-Allow-Origin。具体每个首部信息的含义可以去搜索详细了解下。

我们以 Express 搭建的远程服务为例来说明:

var express = require("express");var cors = require("cors");var app = express();//使用express的cors中间件使其支持跨域请求app.use(cors());app.get("/", function(req, res, next) { res.json({ msg: "This is CORS-enabled for all origins!" });});app.listen(3000, function() { console.log("CORS-enabled web server listening on port 80");});

针对支持 CORS 的服务发起 Ajax 请求最大的特定,客户端即浏览器首先会发送一次请求到服务端判断服务端是否支持跨域请求及是否合法,如果判断通过会回复信息给客户端浏览器,浏览器通过收到的回复信息判断服务端对这次跨域请求是否支持,如果支持就再发送实际的业务请求。所以在这里会有两次请求。

CORS 与 JSONP 对比来说优势比较明显,JSONP 只支持 GET 方式局限性很多,而且 JSONP 并不符合处理业务的正常流程。采用 CORS 的方式,前端编码与正常非跨域请求没有什么不同。在目前很多的 Fake API (模拟接口服务)、Mock Server(数据模拟服务)以及其他公共服务上都很多采用 CORS 的方式来解决跨域问题,例如 json-server 等。

iframe

iframe 与 JSONP 都是使用 src 属性没有跨域限制的特性,iframe 这种方式也不推荐使用,不做详细介绍。

反向代理

既然不能跨域请求,那么我们不跨域就可以了。通过在请求到达服务前部署一个服务,将接口请求进行转发,这就是反向代理。通过一定的转发规则可以将前端的请求转发到其他的服务。以 Nginx 为例:

server { listen 9999 server_name localhost #将所有localhost:9099/api为开头的请求进行转发 location ^~ /api { proxy_pass ; }}

通过反向代理我们将前端后端项目统一通过反向代理来提供对外的服务,这样在前端看上去就跟不存在跨域一样。

反向代理麻烦之处就在原对 Nginx 等反向代理服务的配置,在目前前后端分离的项目中很多都是采用这种方式。

总结

综上所述,CORS 和反向代理是目前使用最多的解决方案,这两个解决方案使用的场景并不相同,我们要根据自身的需求进行选择。公共服务、Fake API 、Mock Server 一般采用 CORS 的方案;而公司前后端分离的项目中更多是采用反向代理的方案。

标签: #ajaxhtml传递参数乱码问题