React跨域

解决方案在二,想简单了解下跨域的可读一。

我们由于项目需要经常会需要对不同域名、不同子域的网站接口发起请求,有时甚至是对于同一域名的不同端口发起请求,此时我们经常看到以下报错:

Access to XMLHttpRequest at 'xxx' from origin 'xxx' has been blocked by CORS 
policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

是的,错误的原因就是你跨域了。刚碰到跨域问题时在网上寻找了大半天,不是报错就是无法跨域转发。最后才发现是react新版本更新了相关规则的缘故。记述下来供大家参考。

一、为什么会有跨域问题?

看到网上举的一个形象例子,先设想下,如果允许跨域,那么黑衣人是不是可以在自己的网页上把请求转发给其他网站?例如,黑衣人在自己的页面设计了一个跨域请求到某钱堆的网址,当用户访问黑衣人网址时,浏览器按照黑衣人设计去访问了钱堆(还携带了用户在钱堆那儿的cookie)......之后,之后警察叔叔们又要加班了。还有诸如此类许多安全隐患。所以后来的浏览器都开始实行同源策略。

同源策略,其实就是只允许相同协议+域名+端口号(如存在)的HTTP请求互相访问。这么理解其实就够了。关于跨域资源共享标准( cross-origin sharing standard )CORS的详细内容,大家可参考这篇文章:链接

本文主要讲React框架下怎么解决跨域问题。

二、怎么解决跨域问题?

这里我给出两种React的跨域解决方案(React16.9亲测可行),第一种比较实用,第二种需要服务端协调。

1.http-proxy-middleware

网上一大片说直接在package.json中配置proxy的,这个方法已经失效很久了。官方给出的新版本解决方案需要借助http-proxy-middleware这个包:

1. npm install http-proxy-middleware 2. src目录下创建setupProxy.js,配置如下:

const proxy = require('http-proxy-middleware')

module.exports = function (app) {
    // proxy第一个参数为要代理的路由
    // 第二参数中target为代理后的请求网址,changeOrigin是否改变请求头,其他参数请看官网
    app.use(proxy('/cityjson', {
        target: 'http://pv.sohu.com',
        changeOrigin: true
    }))
}

3. 测试一下:

//页面代码:
   import React,{ useEffect,useState } from 'react'
   import axios from 'axios';
   
   const App = function () {
       const [ip,setIp] = useState()
   
       useEffect(()=>{
           (async function f(){
               let res = await axios.get('/cityjson') //这里使用搜狐的ip信息查询接口
               setIp(res.data.toString())
           })()
       },[])
   
       return (
           <h1>获取的IP信息:{ip}</h1>
       )
   }
   
   export default App

成功获取!

react 处理跨域axios react 跨域问题怎么解决_服务端

2.借助服务端配置

其实有过服务端开发经验的同学应该一眼就能看出,上面配置setupProxy.js的样子像极了node服务端使用中间件的样子。再看看,http-proxy-middleware,middleware就是中间件的意思。

好了,大概知道了,其实新版本的更新就是想把跨域请求放在服务端去做,而削弱前端跨域的能力(大概是为了安全吧,个人臆想)

在服务端配置的话,只需要在服务端中间件文件里插入http-proxy-middleware即可。express框架和上面的配置基本一样,koa的话参考以下这样:

const Koa = require('koa')
const proxy = require('http-proxy-middleware')

const app = new Koa()

//跨域代理
app.use(async (ctx, next) => {
    if(ctx.url.startsWith('/cityjson')) {
        ctx.respond = false
        return proxy({
            target: 'http://pv.sohu.com', // 服务器地址
            changeOrigin: true,
        })(ctx.req, ctx.res, next)
    }
    return next()
})
......