-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
65 lines (36 loc) · 32.7 KB
/
atom.xml
File metadata and controls
65 lines (36 loc) · 32.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Fr1d4st Blog</title>
<link href="/atom.xml" rel="self"/>
<link href="https://fr1d4st.github.io/"/>
<updated>2019-07-02T13:16:24.904Z</updated>
<id>https://fr1d4st.github.io/</id>
<author>
<name>fr1d4st</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Java中的SPI机制及接口多实现调用</title>
<link href="https://fr1d4st.github.io/2019/07/02/Java%E4%B8%AD%E7%9A%84SPI%E6%9C%BA%E5%88%B6%E5%8F%8A%E6%8E%A5%E5%8F%A3%E5%A4%9A%E5%AE%9E%E7%8E%B0%E8%B0%83%E7%94%A8/"/>
<id>https://fr1d4st.github.io/2019/07/02/Java中的SPI机制及接口多实现调用/</id>
<published>2019-07-02T11:48:26.000Z</published>
<updated>2019-07-02T13:16:24.904Z</updated>
<content type="html"><![CDATA[<h1 id="Java中的SPI机制及接口多实现调用"><a href="#Java中的SPI机制及接口多实现调用" class="headerlink" title="Java中的SPI机制及接口多实现调用"></a>Java中的SPI机制及接口多实现调用</h1><h2 id="0x00-SPI机制"><a href="#0x00-SPI机制" class="headerlink" title="0x00 SPI机制"></a>0x00 SPI机制</h2><blockquote><p>SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。</p></blockquote><p>SPI充分体现了面向接口编程的特点。系统内置接口方法,在实际运行中用户可以自定义实现类来满足不通的实现需求。</p><p>SPI机制在JDK的<code>DriverManager</code>、<code>Spring</code>、<code>Dubbo</code>中得到了充分的利用,<code>Dubbo</code>中更是扩展了SPI机制来实现组件的可扩展性。</p><p><strong>SPI在JDK<code>DriverManager</code>中的使用</strong></p><p>在<code>mysql-connector</code>和<code>ojdbc</code>的jar包中,可以发现在<code>META-INF/services</code>目录下有一个名为<code>java.sql.Driver</code>的文件,在<code>mysql-connector</code>jar包下,文件内容为: </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">com.mysql.cj.jdbc.Driver</span><br></pre></td></tr></table></figure><p>这里就是定义了<code>java.sql.Driver</code>接口的实现类为<code>com.mysql.cj.jdbc.Driver</code>,在<code>java.sql.DriverManager</code>中,通过<code>java.util.ServiceLoader</code>来获取实现类,并实现调用。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">AccessController.doPrivileged(<span class="keyword">new</span> PrivilegedAction<Void>() {</span><br><span class="line"> <span class="function"><span class="keyword">public</span> Void <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"></span><br><span class="line"> ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);</span><br><span class="line"> Iterator<Driver> driversIterator = loadedDrivers.iterator();</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* Load these drivers, so that they can be instantiated.</span></span><br><span class="line"><span class="comment"> * It may be the case that the driver class may not be there</span></span><br><span class="line"><span class="comment"> * i.e. there may be a packaged driver with the service class</span></span><br><span class="line"><span class="comment"> * as implementation of java.sql.Driver but the actual class</span></span><br><span class="line"><span class="comment"> * may be missing. In that case a java.util.ServiceConfigurationError</span></span><br><span class="line"><span class="comment"> * will be thrown at runtime by the VM trying to locate</span></span><br><span class="line"><span class="comment"> * and load the service.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Adding a try catch block to catch those runtime errors</span></span><br><span class="line"><span class="comment"> * if driver not available in classpath but it's</span></span><br><span class="line"><span class="comment"> * packaged as service and that service is there in classpath.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">try</span>{</span><br><span class="line"> <span class="keyword">while</span>(driversIterator.hasNext()) {</span><br><span class="line"> driversIterator.next();</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span>(Throwable t) {</span><br><span class="line"> <span class="comment">// Do nothing</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> println(<span class="string">"DriverManager.initialize: jdbc.drivers = "</span> + drivers);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (drivers == <span class="keyword">null</span> || drivers.equals(<span class="string">""</span>)) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> String[] driversList = drivers.split(<span class="string">":"</span>);</span><br><span class="line"> println(<span class="string">"number of Drivers:"</span> + driversList.length);</span><br><span class="line"> <span class="keyword">for</span> (String aDriver : driversList) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> println(<span class="string">"DriverManager.Initialize: loading "</span> + aDriver);</span><br><span class="line"> Class.forName(aDriver, <span class="keyword">true</span>,</span><br><span class="line"> ClassLoader.getSystemClassLoader());</span><br><span class="line"> } <span class="keyword">catch</span> (Exception ex) {</span><br><span class="line"> println(<span class="string">"DriverManager.Initialize: load failed: "</span> + ex);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><h2 id="0x01-Dubbo中的SPI扩展"><a href="#0x01-Dubbo中的SPI扩展" class="headerlink" title="0x01 Dubbo中的SPI扩展"></a>0x01 Dubbo中的SPI扩展</h2><p>Dubbo中扩展了<code>ServiceLoader</code>为<code>ExtentionLoader</code>,来加载接口的实现类并维护其生命周期。</p><p>定义<code>@SPI</code>注解来标识扩展点的名称,表示可以该接口可以被<code>ExtentionLoader</code>类来加载,接口中的<code>value</code>值表示默认实现。</p><p>定义<code>@Adaptive</code>注解表示方法是一个自适应方法。在调用时会根据方法的参数来决定调用哪个具体的实现类。</p><p>Dubbo也扩展了Java SPI的目录。Dubbo会从以下目录中读取扩展配置信息:</p><ul><li><code>META-INF/dubbo/internal</code></li><li><code>META-INF/dubbo</code></li><li><code>META-INF/services</code></li></ul><p>如LoadBalance接口:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SPI</span>(RandomLoadBalance.NAME)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">LoadBalance</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Adaptive</span>(<span class="string">"loadbalance"</span>)</span><br><span class="line"> <T> <span class="function">Invoker<T> <span class="title">select</span><span class="params">(List<Invoker<T>> invokers, URL url, Invocation invocation)</span> <span class="keyword">throws</span> RpcException</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里<code>RandomLoadBalance.NAME</code>的值为<code>random</code>,在<code>META-INF/dubbo/internal/com.alibaba.dubbo.rpc.cluster.LoadBalance</code>文件中配置了该接口的实现类:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance</span><br></pre></td></tr></table></figure><p>在调用时通过<code>ExtentionLoader</code>来获取实现类:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName);</span><br></pre></td></tr></table></figure><h2 id="0x02-Spring中接口多实现调用"><a href="#0x02-Spring中接口多实现调用" class="headerlink" title="0x02 Spring中接口多实现调用"></a>0x02 Spring中接口多实现调用</h2><h3 id="使用-Qualifier注解"><a href="#使用-Qualifier注解" class="headerlink" title="使用@Qualifier注解"></a>使用<code>@Qualifier</code>注解</h3><p>Spring中<code>@Service</code>提供了<code>value</code>属性,来区分服务名称。并可以通过<code>@Qualifier</code>指定注入的服务;</p><p>如定义如下接口:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">PayService</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">pay</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>分别有如下实现:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span>(<span class="string">"aliPayService"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AliPayService</span> <span class="keyword">implements</span> <span class="title">PayService</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">pay</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span>(<span class="string">"wxPayService"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WxPayService</span> <span class="keyword">implements</span> <span class="title">PayService</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">pay</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在调用的时候就可以使用<code>@ Qualifier</code>指定注入的服务:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="meta">@Qualifier</span>(<span class="string">"wxPayService"</span>)</span><br><span class="line"><span class="keyword">private</span> PayService payService;</span><br></pre></td></tr></table></figure><h3 id="使用工厂模式"><a href="#使用工厂模式" class="headerlink" title="使用工厂模式"></a>使用工厂模式</h3><p>通过<code>ApplicationContext</code>的<code>getBeansOfType</code>获取接口所有实现类并放入容器中,在调用时动态获取实现类;</p><p>如定义如下接口:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">RemoteLockerService</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 获取锁设备厂商</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> 锁设备厂商</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">LockerManufacturerEnum <span class="title">getLockerManufacturer</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 解锁</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> identify 锁唯一标识</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">unLock</span><span class="params">(String identify)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>注入容器:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RemoteLockerServiceFactory</span> <span class="keyword">implements</span> <span class="title">ApplicationContextAware</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Map<LockerManufacturerEnum, RemoteLockerService> lockerServiceMap;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setApplicationContext</span><span class="params">(ApplicationContext applicationContext)</span> </span>{</span><br><span class="line"> lockerServiceMap = <span class="keyword">new</span> HashMap<>();</span><br><span class="line"> Map<String, RemoteLockerService> map = applicationContext</span><br><span class="line"> .getBeansOfType(RemoteLockerService.class);</span><br><span class="line"> map.forEach((key, value) -> lockerServiceMap.put(value.getLockerManufacturer(), value));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <T extends RemoteLockerService> <span class="function">T <span class="title">getRemoteLockerService</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params"> LockerManufacturerEnum lockerManufacturer)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (T) lockerServiceMap.get(lockerManufacturer);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>调用时:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">RemoteLockerService remoteLockerService = RemoteLockerServiceFactory.getRemoteLockerService(locker.getManufacturer());</span><br><span class="line">remoteLockerService.unLock(identify);</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h1 id="Java中的SPI机制及接口多实现调用"><a href="#Java中的SPI机制及接口多实现调用" class="headerlink" title="Java中的SPI机制及接口多实现调用"></a>Java中的SPI机制及接口多实现调用</h1><h2 i
</summary>
<category term="SPI" scheme="https://fr1d4st.github.io/tags/SPI/"/>
</entry>
<entry>
<title>Java Web前后端分离中CORS配置及OPTIONS请求优化</title>
<link href="https://fr1d4st.github.io/2019/06/29/Java-Web%E5%89%8D%E5%90%8E%E7%AB%AF%E5%88%86%E7%A6%BB%E4%B8%ADCORS%E9%85%8D%E7%BD%AE%E5%8F%8AOPTIONS%E8%AF%B7%E6%B1%82%E4%BC%98%E5%8C%96/"/>
<id>https://fr1d4st.github.io/2019/06/29/Java-Web前后端分离中CORS配置及OPTIONS请求优化/</id>
<published>2019-06-29T07:40:04.000Z</published>
<updated>2019-07-01T09:20:38.555Z</updated>
<content type="html"><![CDATA[<h1 id="Java-Web前后端分离中CORS配置及OPTIONS请求优化"><a href="#Java-Web前后端分离中CORS配置及OPTIONS请求优化" class="headerlink" title="Java Web前后端分离中CORS配置及OPTIONS请求优化"></a>Java Web前后端分离中CORS配置及OPTIONS请求优化</h1><h2 id="0x00-CORS-概述"><a href="#0x00-CORS-概述" class="headerlink" title="0x00 CORS 概述"></a>0x00 CORS 概述</h2><blockquote><p>跨域资源共享(<a href="https://developer.mozilla.org/en-US/docs/Glossary/CORS" target="_blank" rel="noopener">CORS</a>) 是一种机制,它使用额外的 <a href="https://developer.mozilla.org/en-US/docs/Glossary/HTTP" target="_blank" rel="noopener">HTTP</a> 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器<strong>不同的域、协议或端口</strong>请求一个资源时,资源会发起一个<strong>跨域 HTTP 请求</strong>。</p><p>跨域资源共享( <a href="https://developer.mozilla.org/en-US/docs/Glossary/CORS" target="_blank" rel="noopener">CORS</a> )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest" target="_blank" rel="noopener"><code>XMLHttpRequest</code></a> 或 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" target="_blank" rel="noopener">Fetch</a> )使用 CORS,以降低跨域 HTTP 请求所带来的风险。</p></blockquote><p>CORS存在的主要原因就是浏览器的同源策略。</p><p><strong>预检请求(preflight request)</strong></p><p>对于跨域请求,浏览器首先通过OPTIONS方法发送一个预检请求,用于判断服务端是否可以接收当前请求,然后才会发送真正的HTTP请求。</p><p><strong>请求头部</strong></p><p>在HTTP请求的头部,主要有如下几个字段和CORS相关:</p><ul><li><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Access-Control-Allow-Origin</span><br></pre></td></tr></table></figure></li></ul><p>该字段用于标识服务端可以接收来自什么地方的请求,为<code>"*"</code>时表示可以接收;</p><ul><li><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Access-Control-Allow-Methods</span><br></pre></td></tr></table></figure></li></ul><p>该字段用于标识服务端可以接收什么样的请求,主要包括<code>GET</code>、<code>POST</code>、<code>OPTIONS</code>、<code>PUT</code>、<code>DELETE</code>等;</p><ul><li><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Access-Control-Allow-Headers</span><br></pre></td></tr></table></figure></li></ul><p>该字段存在预检请求中,用于标识服务端允许的头部内容,主要包括<code>Accept</code>、<code>Accept-Language</code>、<code>Content-Language</code>、<code>Content-Type</code>等,服务端返回内容到<code>Access-Control-Expose-Headers</code>字段;</p><ul><li><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Access-Control-Max-Age</span><br></pre></td></tr></table></figure></li></ul><p>该字段存在预检请求中,用于标识服务端设置的预检请求信息缓存时间。即在服务端设置的时间范围内,只需发送一次OPTIONS请求;</p><ul><li><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Access-Control-Allow-Credentials</span><br></pre></td></tr></table></figure></li></ul><p>该字段存在预检请求中,用于标识是否接收浏览器端的认证信息。认证信息主要包括<code>Cookie</code>、<code>authorization headers</code>等内容。该字段和浏览器中的<code>withCredentials</code>相对应,浏览器端用于标识是否发送认证信息,服务端用于标识是否接收认证信息。</p><h2 id="0x01-Filter中配置CORS"><a href="#0x01-Filter中配置CORS" class="headerlink" title="0x01 Filter中配置CORS"></a>0x01 Filter中配置CORS</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">preHandle</span><span class="params">(ServletRequest request, ServletResponse response)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> HttpServletRequest httpServletRequest = (HttpServletRequest) request;</span><br><span class="line"> HttpServletResponse httpServletResponse = (HttpServletResponse) response;</span><br><span class="line"> httpServletResponse.addHeader(<span class="string">"Access-Control-Allow-Origin"</span>, <span class="string">"path/to/origin"</span>);</span><br><span class="line"> httpServletResponse</span><br><span class="line"> .addHeader(<span class="string">"Access-Control-Allow-Methods"</span>, <span class="string">"GET, POST, OPTIONS"</span>);</span><br><span class="line"> httpServletResponse.setHeader(<span class="string">"Access-Control-Allow-Headers"</span>,</span><br><span class="line"> httpServletRequest.getHeader(<span class="string">"Access-Control-Request-Headers"</span>));</span><br><span class="line"> httpServletResponse.addHeader(<span class="string">"Access-Control-Max-Age"</span>, <span class="string">"86400"</span>);</span><br><span class="line"> httpServletResponse.addHeader(<span class="string">"Access-Control-Allow-Credentials"</span>,<span class="string">"false"</span>);</span><br><span class="line"> <span class="keyword">if</span> (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {</span><br><span class="line"> httpServletResponse.setStatus(HttpStatus.OK.value());</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">super</span>.preHandle(request, response);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="0x02-SpringBoot中配置CORS"><a href="#0x02-SpringBoot中配置CORS" class="headerlink" title="0x02 SpringBoot中配置CORS"></a>0x02 SpringBoot中配置CORS</h2><h3 id="全局配置"><a href="#全局配置" class="headerlink" title="全局配置"></a>全局配置</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CorsConfig</span> <span class="keyword">implements</span> <span class="title">WebMvcConfigurer</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addCorsMappings</span><span class="params">(CorsRegistry registry)</span> </span>{</span><br><span class="line"> registry.addMapping(<span class="string">"path/to/origin"</span>)</span><br><span class="line"> .allowedOrigins(<span class="string">"*"</span>)</span><br><span class="line"> .allowedHeaders(<span class="string">"*"</span>)</span><br><span class="line"> .allowedMethods(<span class="string">"POST"</span>, <span class="string">"GET"</span>, <span class="string">"OPTIONS"</span>)</span><br><span class="line"> .maxAge(<span class="number">86400</span>)</span><br><span class="line"> .allowCredentials(<span class="keyword">false</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="单独配置"><a href="#单独配置" class="headerlink" title="单独配置"></a>单独配置</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@CrossOrigin</span>(</span><br><span class="line"> origins = <span class="string">"path/to/origin"</span>,</span><br><span class="line"> methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS},</span><br><span class="line"> allowedHeaders = <span class="string">"*"</span>,</span><br><span class="line"> allowCredentials = <span class="string">"false"</span>,</span><br><span class="line"> maxAge = <span class="number">86400</span>)</span><br></pre></td></tr></table></figure><h2 id="0x03-OPTIONS请求优化"><a href="#0x03-OPTIONS请求优化" class="headerlink" title="0x03 OPTIONS请求优化"></a>0x03 OPTIONS请求优化</h2><p>右上可知,Access-Control-Max-Age字段用于标识预检请求的缓存时间,因此可以设置Access-Control-Max-Age为较大值来优化OPTIONS请求,在设置的时间段内,只有第一次请求是需要发送OPTIONS的,后面的请求均不需要。</p><p>但是,预检请求只针对于单个URL,而不是整个域名,即对<code>http://domain/a</code>和<code>http://domain/b</code>这2个请求,均需要发送OPTIONS。</p>]]></content>
<summary type="html">
<h1 id="Java-Web前后端分离中CORS配置及OPTIONS请求优化"><a href="#Java-Web前后端分离中CORS配置及OPTIONS请求优化" class="headerlink" title="Java Web前后端分离中CORS配置及OPTIONS
</summary>
<category term="cors" scheme="https://fr1d4st.github.io/tags/cors/"/>
</entry>
</feed>