【原創】Vue使用axios解決SpringBoot跨域Post請求問題

作者:DCTANT

先介紹一下Web端使用的版本情況:

這裏採用了Vue Cli+Webpack的形式搭建的項目,其中Vue版本爲2.9.6,webpack版本爲3.6.0,axios版本爲0.19.0,在2019年9月19日應該算是比較新的版本了。

解決跨域請求問題不是單純前端改改就好的,也不是後端單純改改就好的,需要兩個端配合修改才能解決問題,另外加上Android端也要相應進行配置,當然這三個端我一個人就能解決了,哈哈!

這裏採用的是post json請求的方式,請求後端數據。

1.前端axios配置

  1.1避免session、cookie失效

在main.js中添加上:

import axios from 'axios'

……

中間省略無用代碼

……

axios.defaults.withCredentials = true

如果不加上面這行代碼,則session中無法保存任何信息,包括登錄信息等等,以至於登錄功能無法實現,因此這代碼必須加上!

  1.2設置post方法

我這裏將post請求封裝到一個單獨的js文件中,所以直接上整個function:

function post (interfaceName, form, callback) {
  axios({
    url: constant.url + interfaceName,
    method: 'post',
    data: JSON.stringify(form),
    headers: {
      'Content-Type': 'application/json;charset=utf-8'
    },
    // withCredentials: true
  }).then(object => {
    callback(object.data)
  })
}

由於我是請求整個form(object),因此採用JSON.stringify的方式把整個object轉爲json字符串傳到後端請求。Content-Type使用application/json;charset=utf-8,避免亂碼問題。

說白了前端改的東西非常少,後端纔是最需要改的。

2.後端SpringBoot設置

  2.1Controller增加跨域請求註解

在Controller上加上@CrossOrigin註解

  2.2Filer中增加允許跨域請求的請求頭

這裏直接上代碼:

@WebFilter(filterName = "total",urlPatterns = "/*")
public class TotalFilter implements Filter {
    private ArrayList<String> allowOrigin = new ArrayList<>();

    public TotalFilter() {
        allowOrigin.add("http://127.0.0.1:8080");
        allowOrigin.add("http://localhost:8080");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        String origin = ((HttpServletRequest)servletRequest).getHeader("Origin");
        // INFO: DCTANT: 2019/9/19 設置允許的跨域請求源
        if(allowOrigin.contains(origin)){
            httpServletResponse.setHeader("Access-Control-Allow-Origin",origin);
        }else{
            httpServletResponse.setHeader("Access-Control-Allow-Origin","http://localhost:8080");
        }
        // INFO: DCTANT: 2019/9/19 設置允許的跨域請求頭
        httpServletResponse.setHeader("Access-Control-Allow-Headers","Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With, userId, token, x-requested-with, XMLHttpRequest, Accept");
        // INFO: DCTANT: 2019/9/19 設置允許的跨域請求方法
        httpServletResponse.setHeader("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE");
        // INFO: DCTANT: 2019/9/19 設置允許跨域請求的最長時間,這裏設置了30天,就爲了儘量延長允許時間,
        //  時間過短會導致經常在請求前先發送一個Option請求,用於獲取服務端允許哪些跨域訪問類型,導致資源浪費。
        httpServletResponse.setHeader("Access-Control-Max-Age","2592000");
        // INFO: DCTANT: 2019/9/19 這個非常重要!設置允許攜帶證書信息,包括Session和Cookie等等
        httpServletResponse.setHeader("Access-Control-Allow-Credentials","true");
        // INFO: DCTANT: 2019/9/19 設置請求類型爲json請求 
        httpServletResponse.setContentType("application/json;charset=utf-8");

        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

注意:Filter這個類創好後,要Application類中增加@ServletComponentScan(basePackages = {"***.***.***.filter"}),否則filter不會生效。

  2.3Controller接口配置

3.測試瀏覽器訪問

可以發現所有請求頭都已經加上,能夠正常訪問數據了。

4.Android端請求服務端數據

Android端這裏使用Kotlin+OKhttp+Retrofit的方式訪問服務端

  4.1初始化OKhttp

    private fun initOkhttp(): OkHttpClient {
        return OkHttpClient.Builder()
                .addInterceptor(logger)
                .connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .build()
    }

其中的logger請參考我的個人博客:

https://blog.csdn.net/DCTANT/article/details/96971304

  4.2初始化Retrofit

    private fun initRetrofit(): Retrofit {
        return Retrofit.Builder()
                .client(okHttpClient)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(if (BuildConfig.DEBUG) WebConfig.DEBUG_URL else WebConfig.RELEASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
    }

 

  4.3Retrofit請求用的Interface

    interface RequestInterface {
        @POST
        @Headers("Content-Type:application/json;charset=utf-8")
        fun response(
                @Url url: String,
                @Body any: Any
        ): Observable<ResponseBody>
    }

這裏採用的是觀察ResponseBody的方式進行請求,可以讓Body中傳任何值進去。

  4.4調用接口執行觀察者模式

retrofit.create(RequestInterface::class.java)
.response(requestUrl, form)
.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object : Observer<ResponseBody> {
                    override fun onSubscribe(d: Disposable) {
                        executing = true
                    }

                    override fun onNext(responseBody: ResponseBody) {
                        val string = responseBody.string()
                    }

                    override fun onComplete() {

                    }

                    override fun onError(e: Throwable) {

                    }
                })

 

  4.5測試Android端訪問

可以發現Android端根本不存在跨域請求問題。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章