我是开发者 - 小钿博客

一个小开发仔 ~

分类 "默认分类" 下的文章

处理简单请求和复杂请求之完美跨域CORS

C#后端=>

一、前言
最近在做前后端分离时需要处理跨域问题,遇到的坑在此与大家进行分享,避免多走些弯路。

二、CORS
CORS,常被大家称之为跨越问题,准确的叫法是跨域资源共享(CORS,Cross-origin resource sharing),是W3C标准,是一种机制,它使用额外的HTTP头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
即:请求服务器不同端口的另一个资源,出于安全原因,浏览器限制发起的跨源HTTP请求。

三、解决办法
理跨域问题,必定围绕Access-Control-Allow-Origin来处理。

方案一(交给后端处理)
1、简单请求跨域
处理简单请坟跨域是最简单的,利用WebApi过滤器/拦截器,作用是添加响应头信息
代码如下:

public class ActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext filter)
    {
        //简单请求和复杂请求的统一跨域处理
        filter.Response.Headers.Add("Access-Control-Allow-Origin", HttpHelper.SetAllowOrigin());//HttpHelper.SetAllowOrigin()是动态设置域名,也可以设置"*"表示所有域名
        filter.Response.Headers.Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type");
        filter.Response.Headers.Add("Access-Control-Allow-Methods", "PUT,GET,POST,DELETE,OPTIONS");
        base.OnActionExecuted(filter);
    }
}

简单说明以上代码中出现的HttpHelper.SetAllowOrigin(),作用为动态设置域名,Origin在web.config中配置,多个域名用英文逗号分隔,允许所有域名跨域用"*"
代码如下:

public class HttpHelper
{
    //Access-Control-Allow-Origin设置多个域名
    private static readonly string Origin = ConfigurationManager.AppSettings["Origin"];

    /// <summary>
    /// CORS跨域处理
    /// </summary>
    /// <returns></returns>
    public static string SetAllowOrigin()
    {
        //获取从 HTTP 请求头传过来的 Origin 字段,然后在程序中验证它的值是否合法,并且做出适当的响应
        string requestOrigin = HttpContext.Current.Request.Headers["Origin"];//前端传过来的Origin
        if (Origin == "*") { return Origin; }
        else if (!string.IsNullOrEmpty(Origin) && !string.IsNullOrEmpty(requestOrigin) && Origin.Split(',').Where(s => requestOrigin.Contains(s)).Any()) { return requestOrigin; }
        else { return string.Empty; }
    }
}

2、复杂请求跨域
复杂请求跨域是在简单请求跨域的基础上多了个OPTIONS请求,然而就是这个浏览器发出OPTIONS嗅探比较坑;
处理OPTIONS嗅探的正确姿势:
①在Global的Application_BeginRequest中处理OPTIONS,判断是OPTIONS请求直接放行不做任何处理
代码如下:

protected void Application_BeginRequest()
{
   //CORS跨域复杂请求的OPTIONS嗅探处理
   if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
    {
         //当请求方式是OPTIONS时  ①设置域名允许跨域  ②不返回数据,直接放行
         Response.Headers.Add("Access-Control-Allow-Origin", HttpHelper.SetAllowOrigin());
         Response.Headers.Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type");
         Response.End();
    }
}

②重复(1、简单请求跨域)的操作,此处不再过多说明
③后端同学如果没有强迫症的话跨域处理可以到此为止(瑕疵:复杂请求会调两次接口,先是OPTIONS预检待服务端同意跨域后才真正的提交数据请求接口);有强迫症的同学建议让前端在请求的时候设置一下请求头headers:{'Content-Type':'application/x-www-form-urlencoded'}}或者序列化一下参数QS.stringify(data),设置完后其实也就不会触发CORS的预检请求(preflight);"预检",从而少了后端Global的Application_BeginRequest中处理OPTIONS这一步

以上操作完毕还未能跨域的请检查代码或web.config配置是否正确,例如WebDav未关闭会阻止OPTIONS请求而导致CORS失败
web.config配置如下:

<system.webServer>


<!--<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type" />
    <add name="Access-Control-Allow-Methods" value="PUT,GET,POST,DELETE,OPTIONS"/>
  </customHeaders>
</httpProtocol>

--><!--多域名设置--><!--
<rewrite>
  <outboundRules>
    <rule name="AddCrossDomain">
      <match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" />
      <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
        <add input="{HTTP_ORIGIN}" pattern="(http(s)?://((.+\.)?127.0.0.1:8010))" />
      </conditions>
      <action type="Rewrite" value="{C:0}" />
    </rule>
  </outboundRules>
</rewrite>-->

<modules runAllManagedModulesForAllRequests="true">
  <remove name="WebDavModule" />
</modules>
<handlers>
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="WebDav" />
  <remove name="OPTIONSVerbHandler" />
  <add name="OPTIONS" path="*" verb="OPTIONS" modules="ProtocolSupportModule" resourceType="Unspecified" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers></system.webServer>

最后再整理一下相关知识点
出现发送optiosn请求的原因
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求。

  1. 请求方法是以下三种方法之一:
  • HEAD
  • GET
  • POST
  1. HTTP的头信息不超出以下几种字段:
  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

凡是不同时满足上面两个条件,就属于非简单请求。
当请求存在跨域资源共享(CORS)并且是非简单请求,就会触发CORS的预检请求(preflight);"预检"请求用的请求方法是OPTIONS。实际开发过程中,后台采用token检验机制,前台发送请求必须将token放到Request Header中,那么就需要传输自定义Header信息、或则请求头中的Content-Type="application/json",就会形成非简单请求。

使用 Xcode Server 持续集成 & 打包测试

前言

随着项目的迭代和规范化, 我们可能不满足一直重复的手动编译 打包 发布 测试, 这时就会去寻找一些自动化持续集成的工具, 比如 Jenkins FastLane 等, 但是对于 iOS 开发者来说, 这些非我们熟悉的语言和技术来搭建的工具, 总觉得有那么一点不友好, 那么有没有我们能非常容易上手的持续集成方案呢?

有, 答案就是 Xcode Server, 这个工具在 Xcode 9 之前是要 购买 128 元的 macOS Server 才能使用的, 在 Xcode 9 开始就被集成到了 Xcode 开发工具中来了, 我们可以在自己电脑 或一台专用的 Mac 电脑上, 安装 Xcode, 并启用这个功能, 一个持续集成的服务器就搭建好了.

Xcode Server 有哪些功能呢?

  • 按 时间周期 或者 代码提交 触发持续集成
  • 在构建前或后执行一些脚本, 或发送邮件
  • 直接在 Xcode 中查看集成历史, 错误警告测试等数量, 下载归档或ipa文件, 手动集成等.
  • 也提供了网页版, 上一条的功能基本都有
  • 手机可以打开网页, 选择某次构建直接安装对应App

iOS 12, watchOS 5, macOS Mojave 10.14, tvOS 12 等beta版描述文件下载

Apple 于北京时间 2018/6/5 凌晨1点召开了 WWDC (苹果全球开发者大会), 期间发布了各个系统的新版本, 现在已经提供测试版给开发者下载, 有兴趣下载安装以下文件后, 即可在系统更新中检测到测试版, 可更新体验.

  1. iOS 12 beta:
    iOS_12_Beta_Profile.mobileconfig

  2. watchOS 5 beta:
    watchOS_5_Beta_Profile.mobileconfig

  3. macOS Mojave 10.14 beta:
    macOSDeveloperBetaAccessUtility.dmg

  4. tvOS 12 beta:
    tvOS_12_Beta_Profile.mobileconfig

Git 忽略规则 .gitignore 配置建议, 拯救强迫症

.gitignore 文件

.gitignore 文件是用来描述 Git 忽略规则的文件, 用来防止你提交不必要的文件进入版本控制, 比如个人设置, 编译后的文件等, 一般来说只有源码才能加入版本控制.

GitHub 的建议忽略规则

很多强迫症患者, 建完项目, 要创建 .gitignore 文件时, 就开始纠结了, 总觉得自己填入的规则不全面, 网上找的也不尽相同. 这时候不如我们看看 GitHub 的建议吧, 在 GitHub 有一个 .gitignore 文件模板集合: https://github.com/github/gitignore

大概分为 语言的 和 环境的, 一级目录中的都是 各种语言的 gitignore, Global 目录下都是各种环境的全局 gitignore, 如系统的、和开发工具的忽略规则.

ijkplayer 的编译、打包 framework 和 https 支持

ijkplayerbilibili 开源的一款优秀的播放器, 基于 FFmpeg, 支持 iOS/Android, 点播/直播, 以及多种编码. 官方并不直接提供 framework 框架包, 这样大家可以根据需要选择配置, 自己编译并打包. 但是也让很多第一次使用的小伙伴一脸懵逼, 并且默认配置只支持 http, 如果想播放 https 链接的视频, 那么需要做额外的配置

本文为 iOS 的编译打包过程, 环境为 Mac + Xcode

准备工作

安装 homebrew, git, yasm. (如果已经安装好可以跳过, 不清楚的再来一遍也无妨)

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install git
brew install yasm

隐藏