前端拦截Image的src并返回原生对象

做框架的时候因为跨域问题,需要将用户的请求目标进行hook,拦截用户代码的Image.src操作并重定向到自己的url进行代理访问。为此进行了一些研究。

可能的解决方案

  • 利用Proxy包装并返回Proxy,通过handler拦截。
  • 利用Object.defineProperty监听变化并拦截

利用Proxy方法拦截有个弊端,由于返回的是Proxy对象,虽然能够拦截src并进行修改,但是将无法通过drawImage绘制到Canvas上。

正常的绘制方法:

let canvas2d = document.createElement('canvas').getContext('2d')
let img = new Image()
image.src='a.jpg'
// image会自动请求
image.onload = ()=>{
  canvas2d.drawImage(img,0,0)
  // 成功绘制
}

加了Proxy拦截之后:

function hookFunction(src){
  // hook的url
}
function FakeImage(){
  const img = new Image()
  const handler = {
    set(obj, prop, value) {
    if ((prop === 'src')) {
      console.log('Hook set src',value);
      obj[prop] = hookFunction(src)
    } else {
      return Reflect.set(...arguments);
    }
  }
  }
  return new Proxy(img,handler)
}

let canvas2d = document.createElement('canvas').getContext('2d')
let img = new FakeImage()
image.src='a.jpg'
// image会自动请求
image.onload = ()=>{
  canvas2d.drawImage(img,0,0)
  // 绘制出错,img为Proxy对象,不是HTMLImageElement
}

虽然更改了src但无法绘制到canvas上,我的解决办法是利用Object.defineProperty,同时保存原有的setter来保持HTMLImageElement的自动请求。

function hookFunction(src){
  // hook的url
}
function FakeImage(){
  const img = new Image()

  // 保存原有的setter
  const originalSet = Object.getOwnPropertyDescriptor(img.__proto__,'src').set

  Object.defineProperty(img,'src',{
    set:(src)=>{
      console.log('Hook set src',value)
      // call原来的setter以触发自动请求
      originalSet.call(img,value)
    }
  })
  return img
}

let canvas2d = document.createElement('canvas').getContext('2d')
let img = new FakeImage()
image.src='a.jpg'
// image会自动请求
image.onload = ()=>{
  canvas2d.drawImage(img,0,0)
  // 绘制成功且hook成功
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Spring Boot 中,你可以使用拦截器(Interceptor)来拦截控制器方法的返回对象,并对其进行处理。拦截器可以在控制器方法执行之后、视图渲染之前对返回对象进行操作。 首先,创建一个实现 HandlerInterceptor 接口的拦截器类,它包含三个方法:preHandle、postHandle 和 afterCompletion。在这些方法中,你可以对返回对象进行处理。 ```java @Component public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; // 返回 true 表示继续执行后续的拦截器或控制器方法,返回 false 表示中断后续的执行 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 在视图渲染之前对返回对象进行处理 if (modelAndView != null) { modelAndView.addObject("customAttribute", "customValue"); } } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 执行一些清理操作 } } ``` 接下来,在配置类(通常使用 @Configuration 注解标记)中注册拦截器。 ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private MyInterceptor myInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(myInterceptor).addPathPatterns("/**"); } } ``` 在上述示例中,我们创建了一个名为 MyInterceptor 的拦截器,并将其应用于所有请求路径上。需要注意的是,我们使用了 @Autowired 注解将拦截器注入到配置类中。 当控制器方法执行完毕,但视图渲染之前,拦截器的 postHandle 方法将被调用。在该方法中,你可以对返回对象进行处理,例如向 ModelAndView 对象中添加自定义属性。 注意:拦截器可以用于修改返回对象,但不能直接修改返回的数据。如果你需要修改响应数据,可以考虑使用过滤器(Filter)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值