最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot實現(xiàn)jsonp跨域通信的方法示例

 更新時間:2019年09月17日 10:00:16   作者:inkroom  
這篇文章主要介紹了SpringBoot實現(xiàn)jsonp跨域通信的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

實現(xiàn)jsonp跨域通信

實現(xiàn)基于jsonp的跨域通信方案

原理

瀏覽器對非同源ajax請求有限制,不允許發(fā)送跨域請求

目前跨域解決方案有兩種

  • cros配置
  • jsonp請求

cros為新規(guī)范,通過一個head請求詢問服務(wù)器是否允許跨域,若不允許則被攔截

jsonp則為利用瀏覽器不限制js腳本的同源性,通過動態(tài)創(chuàng)建script請求,服務(wù)器傳遞回一個js函數(shù)調(diào)用語法,瀏覽器端按照js函數(shù)正常調(diào)用回調(diào)函數(shù)

實現(xiàn)思路

首先確定服務(wù)器端應(yīng)該如何返回數(shù)據(jù)

一次正確的jsonp請求,服務(wù)器端應(yīng)該返回如下格式數(shù)據(jù)

jQuery39948237({key:3})

其中, jQuery39948237 為瀏覽器端要執(zhí)行的函數(shù)名,該函數(shù)由ajax庫動態(tài)創(chuàng)建,并將函數(shù)名作為一個請求參數(shù)和該次請求的其余參數(shù)一并發(fā)送,服務(wù)器端無需對此參數(shù)做過多處理

{key:3} 為此次請求返回的數(shù)據(jù),作為函數(shù)參數(shù)傳遞

其次,服務(wù)器端如何處理?

為了兼容jsonp和cros方案,服務(wù)器端應(yīng)該在請求帶有函數(shù)名參數(shù)時返回函數(shù)調(diào)用,否則正常返回json數(shù)據(jù)即可

最后,為了減少代碼的侵入,不應(yīng)該將上述流程放入一個Controller正常邏輯中,應(yīng)該考慮使用aop實現(xiàn)

實現(xiàn)

前端

前端本次使用jquery庫~~(本來想用axios庫的,但是axios不支持jsonp)~~

代碼如下

$.ajax({
    url:'http://localhost:8999/boot/dto',
    dataType:"jsonp",
    success:(response)=>{
      this.messages.push(response);
    }
  })

Jquery默認jsonp函數(shù)名參數(shù)name為 callback

后端

本次采用aop實現(xiàn)

具體思路為: 給Controller添加后切點,判斷request是否有函數(shù)名參數(shù),如果有則修改返回的數(shù)據(jù),沒有則不做處理

而aop又有兩種方案

  1. 常規(guī)aop,自己定義切點
  2. ResponseBodyAdvice,Spring提供的可直接用于數(shù)據(jù)返回的工具類

本次使用第二種方案

首先是Controller的接口實現(xiàn)

@RequestMapping("dto")
public Position dto() {
  return new Position(239, 43);
}

返回一個復(fù)雜類型,Spring會自動對其做json序列化操作

然后的 ResponseBodyAdvice 實現(xiàn)

該類全路徑為: org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice

/**
 * 處理controller返回值,對于有callback值的使用jsonp格式,其余不處理
 */
@RestControllerAdvice(basePackageClasses = IndexController.class)
public class JsonpAdvice implements ResponseBodyAdvice {

  private Logger logger = LoggerFactory.getLogger(getClass());
  @Autowired
  private ObjectMapper mapper;

  //jquery默認是callback,其余jsonp庫可能不一樣
  private final String callBackKey = "callback";

  @Override
  public boolean supports(MethodParameter methodParameter, Class aClass) {
    logger.debug("返回的class={}", aClass);
    return true;
  }

  /**
   * 在此處對返回值進行處理,需要特別注意如果是非String類型,會被Json序列化,從而添加了雙引號,解決辦法見
   *
   * @param body        返回值
   * @param methodParameter  方法參數(shù)
   * @param mediaType     當(dāng)前contentType,非String類型為json
   * @param aClass       convert的class
   * @param serverHttpRequest request,暫時支持是ServletServerHttpRequest類型,其余類型將會原樣返回
   * @param serverHttpResponse response
   * @return 如果body是String類型,加上方法頭后返回,如果是其他類型,序列化后返回
   * @see com.inkbox.boot.demo.converter.Jackson2HttpMessageConverter
   */
  @Override
  public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {

    if (body == null)
      return null;
    // 如果返回String類型,media是plain,否則是json,將會經(jīng)過json序列化,在下方返回純字符串之后依然會被序列化,就會添上多余的雙引號
    logger.debug("body={},request={},response={},media={}", body, serverHttpRequest, serverHttpResponse, mediaType.getSubtype());


    if (serverHttpRequest instanceof ServletServerHttpRequest) {
      HttpServletRequest request = ((ServletServerHttpRequest) serverHttpRequest).getServletRequest();

      String callback = request.getParameter(callBackKey);

      if (!StringUtils.isEmpty(callback)) {
        //使用了jsonp
        if (body instanceof String) {
          return callback + "(\"" + body + "\")";
        } else {
          try {
            String res = mapper.writeValueAsString(body);
            logger.debug("轉(zhuǎn)化后的返回值={},{}", res, callback + "(" + res + ")");

            return callback + "(" + res + ")";
          } catch (JsonProcessingException e) {
            logger.warn("【jsonp支持】數(shù)據(jù)body序列化失敗", e);
            return body;
          }
        }
      }
    } else {
      logger.warn("【jsonp支持】不支持的request class ={}", serverHttpRequest.getClass());
    }
    return body;
  }
}

使用 @RestControllerAdvice 指明切點

bug

經(jīng)過此步驟,理論上即可實現(xiàn)jsonp調(diào)用了。

然而實際測試發(fā)現(xiàn),由于Spring json序列化策略的問題,如果返回jsonp字符串,json序列化之后,將會添上一對引號,如下

應(yīng)該返回

Jquery332({"x":239,"y":43})

實際返回

"Jquery332({\"x\":239,\"y\":43})"

導(dǎo)致瀏覽器端無法正常運行函數(shù)

經(jīng)多方查找資料后得知

由于在 ResponseBodyAdvice 中修改了實際的返回值類型為 String ,而字符串類型經(jīng)過 Jackson 序列化后就會加上引號

解決辦法為:修改默認的json序列化 MessageConverter 處理邏輯,對于實際是 String 的不做處理

代碼如下

@Component
public class Jackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {

  private Logger logger = LoggerFactory.getLogger(getClass());

  @Override
  protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
    if (object instanceof String) {
      //繞開實際上返回的String類型,不序列化
      Charset charset = this.getDefaultCharset();
      StreamUtils.copy((String) object, charset, outputMessage.getBody());
    } else {
      super.writeInternal(object, type, outputMessage);
    }
  }
}


@Configuration
public class MvcConfig implements WebMvcConfigurer {

  private Logger logger = LoggerFactory.getLogger(getClass());

  @Autowired
  private MappingJackson2HttpMessageConverter converter;

  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
//    MappingJackson2HttpMessageConverter converter = mappingJackson2HttpMessageConverter();
    converter.setSupportedMediaTypes(new LinkedList<MediaType>() {{
      add(MediaType.TEXT_HTML);
      add(MediaType.APPLICATION_JSON_UTF8);
    }});
    converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
    converters.add(converter);
  }
}

todo

暫時不明白為什么需要兩個類搭配使用

代碼

具體實現(xiàn)可查閱github

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Http學(xué)習(xí)之組裝報文

    Http學(xué)習(xí)之組裝報文

    這篇文章主要介紹了Http學(xué)習(xí)之組裝報文,組裝報文就是指組裝HTTP響應(yīng)報文,你需要返回客戶請求的相應(yīng)資源,通常一個完整的報文包括報文頭和報文體,一起來看看吧
    2023-04-04
  • Spring Security動態(tài)權(quán)限的實現(xiàn)方法詳解

    Spring Security動態(tài)權(quán)限的實現(xiàn)方法詳解

    這篇文章主要和小伙伴們簡單介紹下 Spring Security 中的動態(tài)權(quán)限方案,以便于小伙伴們更好的理解 TienChin 項目中的權(quán)限方案,感興趣的可以了解一下
    2022-06-06
  • Java RabbitMQ的工作隊列與消息應(yīng)答詳解

    Java RabbitMQ的工作隊列與消息應(yīng)答詳解

    這篇文章主要為大家詳細介紹了Python實現(xiàn)學(xué)生成績管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • 使用IntelliJ?IDEA創(chuàng)建簡單的Java?Web項目完整步驟

    使用IntelliJ?IDEA創(chuàng)建簡單的Java?Web項目完整步驟

    這篇文章主要介紹了如何使用IntelliJ?IDEA創(chuàng)建一個簡單的JavaWeb項目,實現(xiàn)登錄、注冊和查看用戶列表功能,使用Servlet和JSP技術(shù),文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-01-01
  • 代理角色java設(shè)計模式之靜態(tài)代理詳細介紹

    代理角色java設(shè)計模式之靜態(tài)代理詳細介紹

    查了好多資料,發(fā)現(xiàn)還是不全,干脆自己整理吧,至少保證在我的做法正確的,以免誤導(dǎo)讀者,也是給自己做個記錄吧!
    2013-05-05
  • java中實現(xiàn)自定義注解方式

    java中實現(xiàn)自定義注解方式

    注解是Java中的一種元數(shù)據(jù),可以修飾方法、類、參數(shù)和包等,自定義注解需要public修飾符、@interface關(guān)鍵字,以及注解名稱和類型元素,元注解如@Target、@Retention等用于修飾注解,指定注解的適用范圍和生命周期,自定義注解的使用涉及到通過反射解析注解
    2024-11-11
  • SpringMvc接收參數(shù)方法總結(jié)(必看篇)

    SpringMvc接收參數(shù)方法總結(jié)(必看篇)

    下面小編就為大家?guī)硪黄猄pringMvc接收參數(shù)方法總結(jié)(必看篇)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • 微信小程序調(diào)用微信登陸獲取openid及java做為服務(wù)端示例

    微信小程序調(diào)用微信登陸獲取openid及java做為服務(wù)端示例

    這篇文章主要介紹了微信小程序調(diào)用微信登陸獲取openid及java做為服務(wù)端示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • mybatis-plus插入一條數(shù)據(jù),獲取插入數(shù)據(jù)自動生成的主鍵問題

    mybatis-plus插入一條數(shù)據(jù),獲取插入數(shù)據(jù)自動生成的主鍵問題

    這篇文章主要介紹了mybatis-plus插入一條數(shù)據(jù),獲取插入數(shù)據(jù)自動生成的主鍵問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • SpringBoot框架實現(xiàn)支付和轉(zhuǎn)賬功能

    SpringBoot框架實現(xiàn)支付和轉(zhuǎn)賬功能

    在 Spring Boot 框架中實現(xiàn)支付和轉(zhuǎn)賬功能時,涉及到多個細節(jié)和注意點,這些功能通常需要高度的安全性、穩(wěn)定性和可擴展性,本文介紹了實現(xiàn)支付和轉(zhuǎn)賬功能的一些關(guān)鍵點,需要的朋友可以參考下
    2024-08-08

最新評論

太保市| 东乡| 龙州县| 嘉荫县| 文登市| 泸水县| 胶南市| 禄丰县| 筠连县| 大化| 卢湾区| 普定县| 扎鲁特旗| 双城市| 宜城市| 高清| 白银市| 固安县| 涪陵区| 诸暨市| 襄城县| 沙雅县| 哈尔滨市| 清镇市| 朔州市| 景东| 东山县| 拉萨市| 崇明县| 子长县| 泗洪县| 康乐县| 梁山县| 舟曲县| 濮阳县| 府谷县| 白朗县| 阜新| 彩票| 怀柔区| 武义县|