一、背景
有个需求是这样的,客户端直接通过外网访问oss获取图片需要额外付费,考虑到成本问题,修改技术方案为:客户端将请求链接发给后端,后端根据请求做一定的截取或拼接,通过内网调用oss,再将下载下来的图片流返回给前端。
图片流,展现在页面上就是直接返回一张图片在浏览器上。
二、具体代码展示
前端期望,如果异常,直接把http status返回非200
java
@Slf4j
@RestController
public class PictureController {
@Autowired
private PictureService pictureService;
@RequestMapping(value = "getPicture")
public void getPicture(String path, HttpServletResponse resp) {
boolean picSuccess;
// 注意:一定要有这步,否则图片显示不出来
resp.setContentType(MediaType.IMAGE_JPEG_VALUE);
long start = System.currentTimeMillis();
try {
picSuccess = pictureService.getOssPicture(path, resp);
if (!picSuccess) {
resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
}
} catch (Exception e) {
resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
log.error("下载图片失败!!");
}
log.info("cmd=/getPicture,param={},cost:{}", path, System.currentTimeMillis() - start);
}
}
java
public interface PictureService {
boolean getOssPicture(String path, HttpServletResponse resp) throws IOException;
}
java
@Slf4j
@Service
public class PictureServiceImpl implements PictureService {
@Value("${alioss.ak}")
private String accessKeyId;
// http://*********.aliyuncs.com
@Value("${url.prefix}")
private String urlPrefix;
@Value("${oss.connect.time:3000}")
private int ossConnectTime;
@Override
public boolean getOssPicture(String path, HttpServletResponse resp) throws IOException {
String url = getOssUrl(path);
long st = System.currentTimeMillis();
Request requestDownload = new Request.Builder()
.url(url)
.build();
OkHttpClient client = new OkHttpClient();
client = client.newBuilder().connectTimeout(ossConnectTime, TimeUnit.MILLISECONDS).build();
Response responseDownload = client.newCall(requestDownload).execute();
if (responseDownload.isSuccessful() && responseDownload.body() != null && responseDownload.body().byteStream() != null) {
InputStream is = responseDownload.body().byteStream();
writeImageFile(resp, is);
} else {
log.error("PictureServiceImpl-oss调用返回异常: url={}, data={}", url, responseDownload);
return false;
}
long responseTime = System.currentTimeMillis() - st;
log.info("request-oss cost:{}", responseTime);
return true;
}
// base64解码==这块是与前端约定好的,我这边要做的解码
private String getOssUrl(String path) throws UnsupportedEncodingException {
final Base64.Decoder decoder = Base64.getDecoder();
String decodePath = new String(decoder.decode(path), "UTF-8");
StringBuffer buffer = new StringBuffer();
String[] split = decodePath.split("&");
for (int i = 0; i < split.length; i++) {
if (!split[i].startsWith("Version")) {
buffer.append(split[i]).append("&");
}
}
log.info("getOssUrl={}", urlPrefix + buffer);
buffer.append("OSSAccessKeyId=").append(accessKeyId);
return urlPrefix + buffer;
}
/**
* 将输入流输出到页面
*
* @param resp
* @param inputStream
*/
public void writeImageFile(HttpServletResponse resp, InputStream inputStream) {
OutputStream out = null;
try {
out = resp.getOutputStream();
int len = 0;
byte[] b = new byte[1024];
while ((len = inputStream.read(b)) != -1) {
out.write(b, 0, len);
}
out.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
三、总结
上面就是返回图片流的方式;
记录下!