Spring Boot||解决ajax请求跨域问题

背景

最近做一个项目,需要本地上传图片到第三方API,获得其返回的图片链接,将图片链接存入数据库。
理想很美好:找一个第三方图床,了解接口文档 -> Ajax异步发送请求,将图片文件传到第三方图床API -> 接收第三方API返回的数据,从中拿到图片外链 -> 将外链存入数据库
现实很骨感:在我认为最简单的一步,发送Ajax请求时,由于跨域报错了…

已拦截跨源请求:同源策略禁止读取位于 *** 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin'

在这里插入图片描述

需求

有一个第三方接口,我要用ajax请求,出现跨域。在不修改第三方服务器且只能用post提交的前提下,有什么方法能解决跨域问题。(实例:图片文件上传到第三方图床获得外链)

资料

1,第三方api接口文档
由于用到第三方图床,这边把对应图片上传API文档信息共享一下(详情可以看官网:https://sm.ms/)

//接口url
https://sm.ms/api/v2//upload
请求方式post
请求头
Content-Type (String类型)默认值: multipart/form-data
Authorization (String类型)Secret Token(登录后才有,在个人中心查看。有点像用户ID,让对应图片上传成功后到你的账号下)
请求参数
smfile (file类型)待上传的图片文件
format (String)返回类型: json 或 xml, 默认是 json
返回信息参考-见截图-

在这里插入图片描述
2,本地的Ajax请求代码

$.ajax({
	url:"https://sm.ms/api/v2/upload",		//第三方接口url
	data:{	//待上传的数据
		"smfile" : $('#file')[0].files[0]	//$('#file')[0].files[0]是我要上传的图片文件
	},
	type:"post",	//请求方式
	headers: {		//设置请求头
	    "Content-Type":"multipart/form-data",
	    "Authorization":"14ac5******************d079bf"	//替换成自己的token
	},
	success:function(r){	//尝试打印结果
		alert(r);
	},
	error:function(){	//错误提示
		alert("操作失败,请稍后再试...");
	}
})

实现

尝试方法1:ajax请求的数据类型设置成"JSONP"

dataType:"JSONP"

添加完成后,Ajax请求如下:

$.ajax({
	url:"https://sm.ms/api/v2/upload",		
	data:{	
		"smfile" : $('#file')[0].files[0]	
	},
	type:"post",
	dataType:"JSONP",	//设置数据类型
	headers: {		
	    "Content-Type":"multipart/form-data",
	    "Authorization":"14ac5******************d079bf"	
	},
	success:function(r){	
		alert(r);
	},
	error:function(){	//错误提示
		alert("操作失败,请稍后再试...");
	}
})

尝试发送后报错,错误提示如图:
在这里插入图片描述
好家伙,改了数据类型后,确实没有报跨域错误了,但是我的请求方式被强制改成了GET;但是我要访问的第三方接口只支持POST方式的请求,对于GET方式的请求,直接就拒绝了…
所以方法1只能解决用GET方式发送的跨域请求;对于非GET请求的跨域问题,并不能解决失败。所以得试试其他办法。

尝试方法2:CORS
这时候有其他小伙伴给我推荐了CORS。

CORS定义一种跨域访问的机制,可以让AJAX实现跨域访问。CORS 允许一个域上的网络应用向另一个域提交跨域 AJAX。
请求。实现此功能非常简单,只需由服务器发送一个响应标头【response.setHeader(“Access-Control-Allow-Origin”, “"); 】。
如果访问的是对方的API接口,而且允许跨域的话,加上【response.setHeader(“Access-Control-Allow-Origin”, "
”); 】这个标头,就能实现跨域。

看完介绍后我就果断放弃这个方法,因为需要对服务器端进行操作;而我想访问的第三方API,我可没有操作权限…

尝试方法3:利用spring boot(后端)中转转发请求
说实话,这个问题当时困扰了我两天,因为一开始就单纯想通过纯前端发送请求,但是各种方法尝试后均不能如愿。
所以我最后决定借助后端,通过将请求发送给后端,由后端进行访问获得数据,再将数据从后端返回前端来间接实现我的需求。
下面是具体操作和相关代码:

1,前端Ajax请求代码(请求参数带上待上传的图片即可,其他的就按正常的请求来写就好,目标API的请求头等在后端实现)

//数据封装
var formData = new FormData();
formData.append("smfile", $('#file')[0].files[0]);
$.ajax({
	type : "post",
	url : "api/imgGetUrl",	//请求的后端接口url
	data : formData,		// ajax传文件时 一定要指定两个关键性的参数
	contentType:false,  // 1 不用任何编码 因为formdata对象自带编码
	processData:false,  // 2 告诉浏览器不要处理数据 直接发就行
    success : function(r) {
		alert(r);	//输出测试
	})

2,工具类代码(参考的是网上某位大佬的【参考链接:https://www.cnblogs.com/dreammyone/p/6994685.html】,我就加了需要的请求头)

package com.guet.ccbishe.common;import java.io.BufferedReader;

import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;

import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSONObject;

public class InterfaceUtil {

	/**
	 * 表单形式上传数据
	 * 
	 * @param urlStr
	 * @param textMap
	 * @param fileMap
	 * @param contentType 没有传入文件类型默认采用application/octet-stream
	 *                    contentType非空采用filename匹配默认的图片类型
	 * @return 返回response数据
	 */
	@SuppressWarnings("rawtypes")
	public static JSONObject doPost(String urlStr, Map<String, String> textMap, Map<String, MultipartFile> fileMap) {
		JSONObject jsonObject = null;
		HttpURLConnection conn = null;
		// boundary就是request头和上传文件内容的分隔符
		String BOUNDARY = "---------------------------123821742118716";
		try {
			URL url = new URL(urlStr);
			conn = (HttpURLConnection) url.openConnection();
			conn.setConnectTimeout(5000);
			conn.setReadTimeout(30000);
			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.setUseCaches(false);
			conn.setRequestMethod("POST");
			conn.setRequestProperty("Connection", "Keep-Alive");
			conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
			conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
			conn.setRequestProperty("Authorization","DBN****87fQ");//添加的请求头
			
			OutputStream out = new DataOutputStream(conn.getOutputStream());
			// text
			if (textMap != null) {
				StringBuffer strBuf = new StringBuffer();
				Iterator iter = textMap.entrySet().iterator();
				while (iter.hasNext()) {
					Map.Entry entry = (Map.Entry) iter.next();
					String inputName = (String) entry.getKey();
					String inputValue = (String) entry.getValue();
					if (inputValue == null) {
						continue;
					}
					strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
					strBuf.append("Content-Disposition:form-data;name=\"" + inputName + "\"\r\n\r\n");
					strBuf.append(inputValue);
				}
				out.write(strBuf.toString().getBytes());
			}
			// file
			if (fileMap != null) {
				Iterator iter = fileMap.entrySet().iterator();
				while (iter.hasNext()) {
					Map.Entry entry = (Map.Entry) iter.next();
					String inputName = (String) entry.getKey();
					MultipartFile inputValue = (MultipartFile) entry.getValue();
					if (inputValue == null) {
						continue;
					}
					String filename = inputValue.getOriginalFilename();

					// 没有传入文件类型,同时根据文件获取不到类型,默认采用application/octet-stream
					String contentType = inputValue.getContentType();

					StringBuffer strBuf = new StringBuffer();
					strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
					strBuf.append("Content-Disposition:form-data;name=\"" + inputName + "\";filename=\"" + filename
							+ "\"\r\n");
					strBuf.append("Content-Type:" + contentType + "\r\n\r\n");
					out.write(strBuf.toString().getBytes());
					InputStream in = inputValue.getInputStream();
					int bytes = 0;
					byte[] bufferOut = new byte[1024];
					while ((bytes = in.read(bufferOut)) != -1) {
						out.write(bufferOut, 0, bytes);
					}
					in.close();
				}
			}
			byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
			out.write(endData);
			out.flush();
			out.close();

			InputStream inputStream = null;
			if (conn.getResponseCode() != HttpURLConnection.HTTP_OK ) {
				inputStream = conn.getErrorStream();//主要就是这里
			} else {
				inputStream = conn.getInputStream();//主要就是这里
			}
			BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
			StringBuffer buffer = new StringBuffer();
			String line = "";
			while ((line = br.readLine()) != null) {
				buffer.append(line);
			}
			String result = new String(buffer);
			jsonObject = JSONObject.parseObject(result);
			inputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {
				conn.disconnect();
				conn = null;
			}
		}
		return jsonObject;
	}
}

3,后端Java代码(控制层)

@RequestMapping("api/imgGetUrl")
@ResponseBody
public String imgAdd( @RequestParam(value = "smfile", required = false) MultipartFile smfile)  throws IllegalStateException, IOException {
		
	//一、转发地址
	String url = "https://sm.ms/api/v2/upload";
		
	//二、参数处理
	Map<String, MultipartFile> params1 = new HashMap<>();//1 文件类型参数
	params1.put("smfile", smfile);
	
	Map<String, String> params2 = new HashMap<>();//2 字符串类型参数
	params2.put("format", "json");
		
	//三、发送请求-接收返回的数据
	JSONObject result = InterfaceUtil.doPost(url, params2, params1);
	
	//结果返回,这里由于我只要图片地址,所以做了如下处理
    return result.getJSONObject("data").getString("url");
}

4,测试
在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值