Nginx-配置跨越支持

用你最美的姿态,去「跨域」那座山。阅读原文在日常的开放中,我们经常遇到跨域的问题,常用的处理方式都是在代码层添加 cros 支持,但若你有 Nginx 配置权限,在 Nginx 上处理跨域将使得程序异常简单和高效。 代理假设我们的前端域名为 example.com,API 服务架设在 api.example.com 域名下,那我们可以通过代理的形式来配置跨越请求,具体的配置为: 在 Nginx 的 example.com 虚拟主机文件中配置如下的代理配置成功重启后,前端即可用 example.com/api 的方式和 API 交互# /etc/nginx/sites-enabled/example.com.conflocation /api/ { proxy_pass http://api.example.com/; }这种方式的原理是将 API 提供的服务,代理到前端域名的二级目录下,从而避免跨域。 Response Header当然由于很多情况下我们不想将服务代理到前端域名二级目下,那可以通过在 Http Response 中添加 Header 来解决跨越,具体配置如下: # /etc/nginx/snippets/cros.conf;if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,Content-Disposition' always; add_header 'Access-Control-Max-Age' 1728000 always; add_header 'Content-Length' 0; add_header 'Content-Type' 'text/plain; charset=utf-8'; return 204;}if ($request_method ~* "(GET|POST|DELETE|PUT)") { add_header 'Access-Control-Allow-Origin' '*' always;}关于何时会发起 OPTIONS 请求及 OPTIONS 请求的内容,可参考阮老师的这篇文章—— 跨域资源共享 CORS 详解然后在 API 服务域名下添加 CROS 支持即可 ...

May 27, 2019 · 1 min · jiezi

Script-error-问题解法

问题当第三方脚本报错时因为跨域问题不会暴露详细的错误信息,取而代之的是统一的 Script error 我们遇到的情况是页面和js的二级域名一样,并且设置了document.domain,chrome浏览器能够展示详细错误栈;但是很多手机浏览器依然是Script error。 解法我们使用的cdn是阿里云,实际上他已经给出了此问题的解法 阅读之后我们知道只要给script标签添加crossorigin属性就可以了,之后效果如图 具体方法我们项目使用的是webpack,对html进行修饰的插件大家用的应该都是html-webpack-plugin,此插件的衍生插件script-ext-html-webpack-plugin能够满足我们的需求。 plugins: [ .... new HtmlWebpackPlugin({ inject: true, template: paths.appHtmlProd, }), new ScriptExtHtmlWebpackPlugin({ custom: { test: /\.js$/, attribute: 'crossorigin', value: 'anonymous' } }), ...]

May 24, 2019 · 1 min · jiezi

Spring跨域配置

Spring跨域配置介绍跨站 HTTP 请求(Cross-site HTTP request)是指发起请求的资源所在域不同于该请求所指向资源所在的域的 HTTP 请求。比如说,域名A(http://domaina.example)的某 Web 应用程序中通过标签引入了域名B(http://domainb.foo)站点的某图片资源(http://domainb.foo/image.jpg),域名A的那 Web 应用就会导致浏览器发起一个跨站 HTTP 请求。在当今的 Web 开发中,使用跨站 HTTP 请求加载各类资源(包括CSS、图片、JavaScript 脚本以及其它类资源),已经成为了一种普遍且流行的方式。 出于安全考虑,浏览器会限制脚本中发起的跨站请求。比如,使用 XMLHttpRequest 对象发起 HTTP 请求就必须遵守同源策略(same-origin policy)。 具体而言,Web 应用程序能且只能使用 XMLHttpRequest 对象向其加载的源域名发起 HTTP 请求,而不能向任何其它域名发起请求。为了能开发出更强大、更丰富、更安全的Web应用程序,开发人员渴望着在不丢失安全的前提下,Web 应用技术能越来越强大、越来越丰富。比如,可以使用 XMLHttpRequest 发起跨站 HTTP 请求。(这段描述跨域不准确,跨域并非浏览器限制了发起跨站请求,而是跨站请求可以正常发起,但是返回结果被浏览器拦截了。最好的例子是crsf跨站攻击原理,请求是发送到了后端服务器无论是否跨域!注意:有些浏览器不允许从HTTPS的域跨域访问HTTP,比如Chrome和Firefox,这些浏览器在请求还未发出的时候就会拦截请求,这是一个特例。)普通参数跨域在response的头文件添加httpServletResponse.setHeader(“Access-Control-Allow-Origin”,"");httpServletResponse.setHeader(“Access-Control-Allow-Methods”,“POST”);httpServletResponse.setHeader(“Access-Control-Allow-Headers”,“Access-Control”);httpServletResponse.setHeader(“Allow”,“POST”);参数值描述Access-Control-Allow-Origin授权的源控制Access-Control-Allow-Credentialstrue / false是否允许用户发送和处理cookieAccess-Control-Allow-Methods[,]*允许请求的HTTP Method,多个用逗号分隔Access-Control-Allow-Headers[,]控制哪些header能发送真正的请求,多个用逗号分隔Access-Control-Max-Age秒授权的时间,单位为秒。有效期内,不会重复发送预检请求带headr请求跨域这样客户端需要发起OPTIONS请求, 可以说是一个【预请求】,用于探测后续真正需要发起的跨域 POST 请求对于服务器来说是否是安全可接受的,因为跨域提交数据对于服务器来说可能存在很大的安全问题。因为Springmvc模式是关闭OPTIONS请求的,所以需要开启<servlet> <servlet-name>application</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>dispatchOptionsRequest</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup></servlet>开启CORSSpringMVC从4.2版本开始增加了对CORS的支持。在springMVC 中增加CORS支持非常简单,可以配置全局的规则,也可以使用@CrossOrigin注解进行细粒度的配置。使用@CrossOrigin注解先通过源码看看该注解支持的属性在Controller上使用@CrossOrigin注解// 指定当前的AccountController中所有的方法可以处理所有域上的请求@CrossOrigin(origins = {“http://domain1.com”, “http://domain2.com”}, maxAge = 72000L)@RestController@RequestMapping("/account")public class AccountController { @RequestMapping("/{id}") public Account retrieve(@PathVariable Long id) { // … } @RequestMapping(method = RequestMethod.DELETE, path = “/{id}”) public void remove(@PathVariable Long id) { // … }}在方法上使用@CrossOrigin注解@CrossOrigin(maxAge = 3600L)@RestController@RequestMapping("/account")public class AccountController { @CrossOrigin(origins = {“http://domain1.com”, “http://domain2.com”}) @RequestMapping("/{id}") public Account retrieve(@PathVariable Long id) { // … } @RequestMapping(method = RequestMethod.DELETE, path = “/{id}”) public void remove(@PathVariable Long id) { // … }}CORS全局配置除了细粒度基于注解的配置,可以定义全局CORS的配置。这类似于使用过滤器,但可以在Spring MVC中声明,并结合细粒度@CrossOrigin配置。默认情况下所有的域名和GET、HEAD和POST方法都是允许的。基于XML的配置<mvc:cors> <mvc:mapping path="/api/" allowed-origins=“http://domain1.com, http://domain2.com” allowed-methods=“GET, POST, PUT, HEAD, PATCH, DELETE, OPTIONS, TRACE” allowed-headers=“header1, header2, header3” exposed-headers=“header1, header2” allow-credentials=“false” max-age=“72000” /> <mvc:mapping path="/resources/" allowed-origins=“http://domain3.com” /></mvc:cors>基于代码的配置这个方法同样适用于SpringBoot。@Configurationpublic class WebConfig extends WebMvcConfigurerAdapter { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/") .allowedOrigins(“http://domain1.com”) .allowedOrigins(“http://domain2.com”) .allowedMethods(“GET”, “POST”, “PUT”, “HEAD”, “PATCH”, “DELETE”, “OPTIONS”, “TRACE”); .allowedHeaders(“header1”, “header2”, “header3”) .exposedHeaders(“header1”, “header2”) .allowCredentials(false) .maxAge(72000L); registry.addMapping("/resources/") .allowedOrigins(“http://domain3.com”); }}基于过滤器的配置import org.springframework.web.cors.CorsConfiguration;import org.springframework.web.cors.UrlBasedCorsConfigurationSource;@Beanpublic FilterRegistrationBean corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.addAllowedOrigin(“http://domain1.com”); config.addAllowedOrigin(“http://domain2.com”); config.addAllowedHeader(""); config.addAllowedMethod(“GET, POST, PUT, HEAD, PATCH, DELETE, OPTIONS, TRACE”); config.setAllowCredentials(true); config.setMaxAge(72000L); // CORS 配置对所有接口都有效 source.registerCorsConfiguration("/**", config); FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source)); bean.setOrder(0); return bean;} ...

January 9, 2019 · 2 min · jiezi

跨域

前端跨域的各种知识点每次复习基础知识的时候,都会看一些有关跨域的知识点。但在工作中从来没有用到过。恰巧,前几天官网的同事让我请求他们的接口,并指明需要用到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 jsonpjsonp是利用动态添加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… ...

December 19, 2018 · 1 min · jiezi