天天看点

axios get怎么还会显示跨域_react+axios用node代理解决跨域

今天自己搭了个react架子,网上找了个公开的接口,结果发现跨域了。因为接口是别人的,我没法让别人在接口上处理跨域问题,而且这个接口是post请求方式,也没发用jsop处理跨域。

一、前端处理跨域

1、利用proxy代理

特点:这种方式简单易用,不受接口类型限制,get,post等都能支持,适用于与前后端分离的项目。

使用方式:

找到package.json文件,在里面加上 proxy:代理接口地址,重新启动项目即可。

"proxy": "http://10.99.206.102:9992/api/v1"

axios get怎么还会显示跨域_react+axios用node代理解决跨域

proxy

需要注意的是,若使用本方法代理跨域,且开启了全局配置的公共接口地址,一定记得将公共接口地址配置为空。我项目一般使用的axios,需要将这个全局配置改为空。axios.defaults.baseURL = ""

随便请求一个接口,看看接口是不是走的自己电脑的ip或者localhost,若不是就证明代理跨域没成功,检查下接口配置有没有清理。

2、利用jsonp处理get请求

若只是想处理单个get请求的跨域,直接使用jsonp方式即可。这个项目中基本没用,有需要的话,自己百度看看怎么操作的。

二、node代理跨域

总体思路,就是直接让node去掉这个跨域的接口(因为服务器端不存在跨域,所以node调用接口是没毛病的),拿到结果。然后在node端抛出这个路由,前端调用这个接口就可以了。但是我的react是脚手架启动的,并不是我写的node启动的,所以端口还是不一样,这样还是有跨域问题,这时候的跨域问题就很好解决了,在后端配置下cros就好了。

当然,这种方式比较麻烦,一般工作中后台直接处理跨域就可以了,不需要单独再启动node处理跨域。这里就是记录下node一个完整的调用过程,java处理跨域也是一样开启一个cros即可。

闲话不多说,我直接把代码附上,然后把写代码过程中遇到的问题总结下。

我调用的公共接口是 图灵机器人 里的接口

接口地址:

我是直接用create-react-app搭建的项目,然后把src下面的目录都删掉,自己建了两个文件,index.js和index.css

最终的文件目录结构如下:

axios get怎么还会显示跨域_react+axios用node代理解决跨域

文件目录

src/index.js文件如下:

import React from 'react'

import ReactDOM from 'react-dom'

import axios from 'axios'

import './index.css'

class Layout extends React.Component{

constructor(){

super()

this.state={

content:'',

value:'zoey'

}

}

componentDidMount(){

let data1

axios.post('http://www.tuling123.com/openapi/api',{

info:'今天我最美',

userId:1234

}).then(data=>{

console.log(data)

data1 = data

})

this.setState({

content:data1

})

}

render(){

debugger

const obj = this.state.content

let one = []

for( var item in obj){

one.push( item=='text'? obj[item]:'')

}

return

我是头部信息

{one}

}

}

ReactDOM.render(

,

document.querySelector('#root')

)

这里就会发现报错

axios get怎么还会显示跨域_react+axios用node代理解决跨域

跨域

因为同源策略,导致这里跨域,我就开始搭建了个node服务器,代码如下:

建了个文件夹server,里面新建3个文件server.js routes.js home.js

server/server.js的代码:

const Koa= require('koa')

const app = new Koa()

const routes = require('./routes.js');

//路由

app.use(routes());

app.listen(3001,()=>{

console.log('port is running at 3001')

})

server/routes.js的代码

const compose = require('koa-compose');

const Router = require('koa-router');

var router = new Router();

const Home = require('./home');

router.get('/api/index', Home.index)

// app.use(router.routes()).use(router.allowedMethods());

module.exports = (ctx, next) => compose([router.routes(), router.allowedMethods()]);

server/home.js的代码:

const axios = require('axios')

class Home {

static async index(ctx,next){

const {info,userId} =ctx.request.query

const {data} = await axios.post('http://www.tuling123.com/openapi/api',{

key:'c9d1eb9811e648a49ece24b7cb1065e9',

info:info,

userId:userId

})

console.log(data)

ctx.body=data

}

}

module.exports = Home

然后启动这个server,为了方便我就没配置,直接手动切换到server目录下,node server.js启动项目,这样这个服务器就抛出了可以localhost:3001/api/index这个接口了,这个接口返回的结果就是我们所需的了。

现在改改src/index.js中componentDidMount中的代码

componentDidMount(){

let data

//注意,这里3001 就是node启用的端口

axios.get('http://localhost:3001/api/index',{

params:{ info:'今天我最美',

userId:1234}

}).then(req=>{

{data} = req

})

this.setState({

content:data

})

}

这里你就发现一个问题了,又一次出现了跨域,那现在这个跨域就很好解决了,配置下服务端代码就可以了,我直接在server/server.js中用了koa-cros这个插件就可以啦,这里注意,cors一定要放在路由的上面。

const Koa= require('koa')

const app = new Koa()

const routes = require('./routes.js');

const cors = require('koa2-cors');

//运行跨域

app.use(cors());

//路由

app.use(routes());

app.listen(3001,()=>{

console.log('port is running at 3001')

})

配置好了以后,又发现data取不到数据,这里因为axios是异步的,数据还没有获取,页面已经渲染完成了。因为axios返回的是一个promise,所以这里可以把componentDidMount改成异步等待的方法,取得data的值

async componentDidMount(){

//注意,这里3001 就是node启用的端口

const {data}= await axios.get('http://localhost:3001/api/index',{

params:{ info:'今天我最美',

userId:1234}

})

this.setState({

content:data

})

}

这样数据就能显示了

在调用过程中发现我对于post方式里的Content-Type 的参数不是很清楚,下面我总结下Content-Type 几种常用的参数的使用场景:(这里为转载)

application/x-www-form-urlencoded

这应该是最常见的 POST 提交数据的方式了。浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。请求类似于下面这样

POST http://www.example.com HTTP/1.1

Content-Type: application/x-www-form-urlencoded;charset=utf-8

title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

首先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持。例如 PHP 中,

axios get怎么还会显示跨域_react+axios用node代理解决跨域

_POST[‘sub’] 可以得到 sub 数组。

很多时候,我们用 Ajax 提交数据时,也是使用这种方式。例如 JQuery 和 QWrap 的 Ajax,Content-Type 默认值都是「application/x-www-form-urlencoded;charset=utf-8」。

multipart/form-data

这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 form 的 enctyped 等于这个值。直接来看一个请求示例:

POST http://www.example.com HTTP/1.1

Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

------WebKitFormBoundaryrGKCBY7qhFd3TrwA

Content-Disposition: form-data; name="text"

title

------WebKitFormBoundaryrGKCBY7qhFd3TrwA

Content-Disposition: form-data; name="file"; filename="chrome.png"

Content-Type: image/png

PNG ... content of chrome.png ...

------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 mutipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 –boundary 开始,紧接着内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 –boundary– 标示结束。关于 mutipart/form-data 的详细定义,请前往 rfc1867 查看。

这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段原生 form 表单也只支持这两种方式。但是随着越来越多的 Web 站点,尤其是 WebApp,全部使用 Ajax 进行数据交互之后,我们完全可以定义新的数据提交方式,给开发带来更多便利。

application/json

application/json 这个 Content-Type 作为响应头用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。

JSON 格式支持比键值对复杂得多的结构化数据,这一点也很有用。

例如下面这段代码:

var data = {'title':'test', 'sub' : [1,2,3]};

$http.post(url, data).success(function(result) {

...

});

最终发送的请求是:

POST http://www.example.com HTTP/1.1

Content-Type: application/json;charset=utf-8

{"title":"test","sub":[1,2,3]}

这种方案,可以方便的提交复杂的结构化数据,特别适合 RESTful 的接口。各大抓包工具如 Chrome 自带的开发者工具、Firebug、Fiddler,都会以树形结构展示 JSON 数据,非常友好。但也有些服务端语言还没有支持这种方式,例如 php 就无法通过 $_POST 对象从上面的请求中获得内容。这时候,需要自己动手处理下:在请求头中 Content-Type 为 application/json 时,从 php://input 里获得原始输入流,再 json_decode 成对象。

text/xml

它是一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范。XML-RPC 协议简单、功能够用,各种语言的实现都有。JavaScript 中,也有现成的库支持以这种方式进行数据交互,能很好的支持已有的 XML-RPC 服务。